欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android集成腾讯TBS浏览服务

程序员文章站 2022-08-20 13:18:24
背景在使用Android的webview嵌套页面,从而打包成APP,实现apk。但是,文件下载功能出现了问题,总是下载不了。TBS官网介绍:腾讯浏览服务是致力于优化移动端webview体验的整套解决方案。该方案由SDK、手机QQ浏览器X5内核和X5云端服务组成,解决移动端webview使用过程中出现的一切问题,优化用户的浏览体验。同时,腾讯还将持续提供后续的更新和优化,为开发者提供最新最优秀的功能和服务。集成可查看官网快速接入试试水初始化 x5,创建 MyAplication 类:im...

背景

在使用Android的webview嵌套页面,从而打包成APP,实现apk。但是,文件下载功能出现了问题,总是下载不了。

TBS

官网介绍
腾讯浏览服务是致力于优化移动端webview体验的整套解决方案。该方案由SDK、手机QQ浏览器X5内核和X5云端服务组成,解决移动端webview使用过程中出现的一切问题,优化用户的浏览体验。同时,腾讯还将持续提供后续的更新和优化,为开发者提供最新最优秀的功能和服务。

集成

可查看官网快速接入

试试水

  1. 初始化 x5,创建 MyAplication 类:
import android.app.Application;
import android.util.Log;

import com.tencent.smtt.sdk.QbSdk;

public class MyAplication extends Application {
    @Override
    public void onCreate() {
// TODO Auto-generated method stub
        super.onCreate();
        initX5();
    }
    /**
     * 初始化X5
     */
    private void initX5() {
//x5內核初始化回调
        QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
            @Override
            public void onViewInitFinished(boolean arg0) {
// TODO Auto-generated method stub
//x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
                Log.d("app", " onViewInitFinished is " + arg0);
            }
            @Override
            public void onCoreInitFinished() {
// TODO Auto-generated method stub
            }
        };
//x5内核初始化接口
        QbSdk.initX5Environment(getApplicationContext(), cb);
    }
}
  1. 在layout xml 添加 WebView
<com.tencent.smtt.sdk.WebView
        android:id="@+id/webview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
  1. 使用腾讯tbs webview 加载url,在 MainActivity 中添加
WebView mWebView = (com.tencent.smtt.sdk.WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);// 支持js
mWebView.setWebViewClient(new WebViewClient());//防止加载网页时调起系统浏览器
mWebView.loadUrl("http://192.168.16.87/wechat/login.html?t=" + new Date().getTime());

注意: webview 使用的包为: com.tencent.smtt.sdk.*

结果

tbs 加载网页速度加快了不少,但是依旧下载不了。23333333

再次探索

通过查看 TBS Api 发现 shouldOverrideUrlLoading 方法可监听 url 的变化。思路:
通过 文件的url,通知Android 去下载文件,然后使用QbSdk.openFileReader 去实现文件打开。

下载工具类

  1. 在 app - build.gradle - dependencies 添加:
 compile 'com.squareup.okhttp3:okhttp:3.4.1'
 compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.1'
  1. 添加 DownloadUtil 类:
package utils;



import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * Created by yufs on 2017/8/16.
 */

public class DownloadUtil {
    public static final int DOWNLOAD_FAIL=0;
    public static final int DOWNLOAD_PROGRESS=1;
    public static final int DOWNLOAD_SUCCESS=2;
    private static DownloadUtil downloadUtil;
    private final OkHttpClient okHttpClient;
    public static DownloadUtil getInstance() {
        if (downloadUtil == null) {
            downloadUtil = new DownloadUtil();
        }
        return downloadUtil;
    }

    private DownloadUtil() {
        okHttpClient = new OkHttpClient();
    }

    /**
     *
     */
    public void download(final String url,final String saveDir,final OnDownloadListener listener){
        this.listener=listener;
        Request request=new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Message message=Message.obtain();
                message.what=DOWNLOAD_FAIL;
                mHandler.sendMessage(message);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream is=null;
                byte[] buf=new byte[2048];
                int len=0;
                FileOutputStream fos=null;
                //储存下载文件的目录
                String savePath=isExistDir(saveDir);
                try{
                    is=response.body().byteStream();
                    long total=response.body().contentLength();
                    File file=new File(savePath,getNameFromUrl(url));
                    fos=new FileOutputStream(file);
                    long sum=0;
                    while((len = is.read(buf))!=-1){
                        fos.write(buf,0,len);
                        sum+=len;
                        int progress=(int)(sum*1.0f/total*100);
                        //下载中
                        Message message=Message.obtain();
                        message.what=DOWNLOAD_PROGRESS;
                        message.obj=progress;
                        mHandler.sendMessage(message);

                    }
                    fos.flush();
                    //下载完成
                    Message message=Message.obtain();
                    message.what=DOWNLOAD_SUCCESS;
                    message.obj=file.getAbsolutePath();
                    mHandler.sendMessage(message);
                }catch (Exception e){
                    Log.d("down",e.toString());
                    Message message=Message.obtain();
                    message.what=DOWNLOAD_FAIL;
                    mHandler.sendMessage(message);
                }finally{
                    try{
                        if(is!=null)
                            is.close();
                    }catch (IOException e){

                    }
                    try {
                        if(fos!=null){
                            fos.close();
                        }
                    }catch (IOException e){

                    }
                }
            }
        });
    }

    private String getNameFromUrl(String url) {
        return url.substring(url.lastIndexOf("/")+1);
    }


    private String isExistDir(String saveDir) throws IOException {
        File downloadFile=new File(saveDir);
        if(!downloadFile.mkdirs()){
            downloadFile.createNewFile();
        }
        String savePath=downloadFile.getAbsolutePath();
        return savePath;
    }




    private Handler mHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case DOWNLOAD_PROGRESS:
                    listener.onDownloading((Integer) msg.obj);
                    break;
                case DOWNLOAD_FAIL:
                    listener.onDownloadFailed();
                    break;
                case DOWNLOAD_SUCCESS:
                    listener.onDownloadSuccess((String) msg.obj);
                    break;
            }
        }
    };


    OnDownloadListener listener;
    public interface OnDownloadListener{
        /**
         * 下载成功
         */
        void onDownloadSuccess(String path);
        /**
         * 下载进度
         * @param progress
         */
        void onDownloading(int progress);
        /**
         * 下载失败
         */
        void onDownloadFailed();
    }
}

webview 查看文件


    final Context ctx = this;
     mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                Log.d("app", " 网址 is " + url);
                int i = url.indexOf("file");
                if (i != -1) {
                    Log.d("app", " 网址 is " + url);


                    progressDialog.show();

                    /**
                     *  下载文件
                     */
                    DownloadUtil.getInstance().download(url,  ctx.getExternalCacheDir().getPath(), new DownloadUtil.OnDownloadListener() {
                        @Override
                        public void onDownloadSuccess(final String path) {

                            Log.d("app", " 下载成功 " + path);

                       
                            /**
                             *  打开文件
                             */
                            HashMap<String, String> params = new HashMap<String, String>();
                            params.put("style", "1");
                            params.put("local", "true");
                            QbSdk.openFileReader(ctx,path, params, new ValueCallback<String>() {
                                @Override
                                public void onReceiveValue(String s) {

                                }
                            });


                        }

                        @Override
                        public void onDownloading(int progress) {
                            Log.d("app","已下载"+progress+"%");
                        }

                        @Override
                        public void onDownloadFailed() {
                            Log.d("app", " 下载失败  ");
                        }
                    });
                    return  true;
                }

                //这里可以对特殊scheme进行拦截处理
                return false;//要返回true否则内核会继续处理
            }
        });

问题

  1. 文件路径出现拒绝访问
  2. 网络不可使用
  3. 手机横竖屏导致webview重新加载

解决

  1. 在res 创建xml文件夹:
    创建 x5webview_file_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="sdcard" path="."/>
    <external-path name="path" path="Android/data/com.package.ride/path"/>
</paths>

创建 network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>
  1. AndroidManifest.xml 配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mywebapplication">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


    <!--   网络   android:requestLegacyExternalStorage...  android:networkSecurityConfig...-->
    <application
        android:requestLegacyExternalStorage="true"
        android:networkSecurityConfig="@xml/network_security_config"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true"
        android:theme="@style/AppTheme">
        <!--   横竖屏重新加载  android:configChanges... -->
        <activity

          android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
            android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
<!--       文件路径 问题   -->
        <provider
            android:name="com.tencent.smtt.utils.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/x5webview_file_paths" />
        </provider>
        <service
            android:name="com.tencent.smtt.export.external.DexClassLoaderProviderService"
            android:label="dexopt"
            android:process=":dexopt" >
        </service>
    </application>


</manifest>

源码

本文地址:https://blog.csdn.net/weixin_42429220/article/details/108992090