android离线集成x5内核,一个前端人的踩坑之路~

1,331 阅读4分钟

前言

最近在做一个电视看版,拿到需求第一想法就是使用hybrid 开发模式,由于没有android开发人员,所以都得我一个完成(2023.02.01)。

demo编写 -> 测试

开始查找资料,创建android项目,加载百度的地址🤦‍♀,见证结果,公司几个android 8以上的手机都可以,打包apk在电视安装,也没有问题。切换成自己写的前端vue3项目,手机都可以运行,但是安装在电视上面就是白板,一直loading中😭

踩坑中

百度的网页可以运行,自己还特意搭建了nginx静态资源环境,反正各种折腾,猜测应该是用了比较新的语法,开始疯狂百度,查看官网文档,问下群友,最后决定试试集成x5内核腾讯X5服务。吐槽下官网描述的东西太少,资料感觉没怎么更新。

下载官网的demo,上午运行正常,下午怎么安装都内核都安装不成功,而且首次还加载的是sdk内核,需要杀掉进程,再次重启才能运行x5内核。

继续踩坑中。。。

x5下载到本地,内核安装成功则初始化webview,不然首次加载还是sdk内核。

核心代码

MainActivity.java

public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks {

    private final String TAG = "MainActivity";

    private String[] perms = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.ACCESS_NETWORK_STATE};

    private int CODE_REQUEST_PERMISSION = 101;

    private WebView mWebView;
    private TextView mTextView;
    private LinearLayout mLinearLayout;

    private Timer timer = new Timer();

    private int second = 0;

    private X5Util x5Util;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(layout.activity_main);
        mTextView = findViewById(id.load_view);
        mLinearLayout = findViewById(id.tv_liner);
        if (EasyPermissions.hasPermissions(this, perms)) {
            startCheck();
        } else {
            EasyPermissions.requestPermissions(this, "", CODE_REQUEST_PERMISSION, perms);
        }
    }


    /**
     * 初始化weview
     */
    private void initWebview() {
        mWebView = new WebView(this);
        //定义子View中两个元素的布局
        ViewGroup.LayoutParams vlp = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);

        mWebView.setLayoutParams(vlp);
        mLinearLayout.addView(mWebView);

        WebSettings webSetting = mWebView.getSettings();
        webSetting.setAllowContentAccess(true);
        webSetting.setAllowFileAccess(true);
        webSetting.setTextZoom(100);
        webSetting.setCacheMode(WebSettings.LOAD_DEFAULT);
        webSetting.setAllowFileAccessFromFileURLs(true);
        webSetting.setJavaScriptEnabled(true);
        mWebView.addJavascriptInterface(this, "x5");
        mWebView.setWebChromeClient(new MyChromeClient());
        mWebView.setWebViewClient(new MyWebViewClient());

        mWebView.loadUrl("xxx.xx.xx"); // 地址

    }

    /**
     * 开始检测x5内核
     */
    private void startCheck() {

        int version = QbSdk.getTbsVersion(this);
        Log.d(TAG, String.valueOf(version));
        // 如果没有安装x5内核则进行安装
        if (QbSdk.getTbsVersion(this) <= 0) {
            // 初始化x5util
            x5Util = new X5Util(this, new LocalInstallListener() {
                @Override
                public void onSuccess() {
                    timer.cancel();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            initWebview();
                            String message = mWebView.getIsX5Core() ? "X5内核: " + QbSdk.getTbsVersion(MainActivity.this) : "SDK系统内核";
                            Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
                        }
                    });
                }

                @Override
                public void onError(String message) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "内核安装失败,请重启!", Toast.LENGTH_SHORT).show();
                        }
                    });
                    timer.cancel();
                }
            });

            customTimer();
            // 子线程安装内核
            new Thread(new Runnable() {
                @Override
                public void run() {
                    x5Util.startInstallX5();
                }
            }).start();//启动线程
        } else {
            initWebview();
            String message = mWebView.getIsX5Core() ? "X5内核: " + QbSdk.getTbsVersion(this) : "SDK系统内核";
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 定时器,定时更新状态
     */
    private void customTimer() {
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        second++;
                        Log.d(TAG, String.valueOf(second));
                        mTextView.setText("内核初始化中" + String.valueOf(second) + "s" + "...");
                    }
                });
            }
        }, 0, 1000);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);

    }

    @Override
    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
        if (CODE_REQUEST_PERMISSION == requestCode) {
            startCheck();
        }
    }

    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
        Toast.makeText(this, "权限获取失败", Toast.LENGTH_SHORT).show();

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:id="@+id/load_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:textSize="16dp"
    android:text="正在加载内核..."/>
    <LinearLayout
        android:id="@+id/tv_liner"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"></LinearLayout>

</RelativeLayout>

AndroidManifest.xml 权限配置

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

X5Util.java

public class X5Util {
    private final String TAG = "X5Util";

    /**
     * 内核存放的文件夹
     */
    private String DIR =
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();

    /**
     * 内核版本号
     */
    private final int CORE_VERSION = 46141;

    /**
     * 内核文件名称
     */
    private final String CORE_NAME = "tbs_core_046141.apk";

    /**
     * 内核文件路径
     */
    private String CORE_PATH = DIR + File.separator + CORE_NAME;


    /**
     * 上下文
     */
    private Context mContext;

    /**
     * 离线内核安装监听
     */
    private LocalInstallListener mLocalInstallListener;

    public X5Util(Context context, LocalInstallListener listener) {
        this.mContext = context;
        this.mLocalInstallListener = listener;
    }

    /**
     * 是否初始化x5成功
     *
     * @param context 上下文环境
     * @return
     */
    public Boolean isInited(Context context) {
        int version = QbSdk.getTbsVersion(context);
        return version > 0;
    }

    /**
     * 开始安装x5内核
     */
    public void startInstallX5() {

        /**
         *  校验手机abi型号
         */
        String abi = Build.CPU_ABI;

        //内核型号匹配则直接进行离线内核安装
        if ("arm64-v8a".equals(abi)) {
            Boolean isExitCore = copyX5Core();
            if (isExitCore) {
                // 存在内核文件
                startInstallX5();
            }
        } else {
            Log.d(TAG, "内核型号不匹配,无法进行本地离线安装内核");
        }
    }

    /**
     * 开始安装本地离线内核
     */
    private void startInstallX5() {
        try {
            QbSdk.installLocalTbsCore(mContext, CORE_VERSION, CORE_PATH);
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    int version = QbSdk.getTbsVersion(mContext);
                    if (version > 0) {
                        timer.cancel();
                        Log.d(TAG, "循环检验内核版本" + String.valueOf(version));
                        QbSdk.initX5Environment(mContext, new QbSdk.PreInitCallback() {
                            @Override
                            public void onCoreInitFinished() {
                                Log.d(TAG, "onCoreInitFinished");
                            }

                            @Override
                            public void onViewInitFinished(boolean b) {
                                Log.d(TAG, "onViewInitFinished_p0=$p0");
                            }
                        });
                        mLocalInstallListener.onSuccess();
                    } else {
                        QbSdk.initX5Environment(mContext, new QbSdk.PreInitCallback() {
                            @Override
                            public void onCoreInitFinished() {
                                Log.d(TAG, "onCoreInitFinished");
                            }

                            @Override
                            public void onViewInitFinished(boolean b) {
                                Log.d(TAG, "onViewInitFinished_p0=$p0");
                            }
                        });

                        Log.d(TAG, "循环检验内核版本" + String.valueOf(version));
                    }
                }
            }, 0, 1000);

        } catch (Exception e) {
            Log.d(TAG, "本地离线内核安装异常,异常信息>" + e.getMessage());
        }

    }

    /**
     * 将内核文件拷贝到指定目录
     */
    private Boolean copyX5Core() {
        File file = null;
        try {
            // 目录存在,则将assets中的内核文件复制进去
            file = new File(CORE_PATH);
            Log.d(TAG, "文件路径:" + CORE_PATH);

            if (file.exists()) {
                // 如果文件存在,为了确保文件完整性,需要删除后重新从项目中复制进去
                Log.d(TAG, "删除文件!");
                file.delete();
            }

            // 开始复制文件到指定目录
            InputStream ins = mContext.getResources().getAssets().open(CORE_NAME);
            Log.d(TAG, "开始读取内核文件");
            FileOutputStream fos = new FileOutputStream(file);
            Log.d(TAG, "开始拷贝内核文件");
            byte[] buffer = new byte[1024];
            int count = 0;
            // 循环写出
            while ((count = ins.read(buffer)) > 0) {
                fos.write(buffer, 0, count);
            }
            fos.close();
            ins.close();
            Log.d(TAG, "拷贝内核文件完成");
            return true;
        } catch (Exception e) {
            Log.d(TAG, "拷贝内核文件异常,异常信息>" + e.getMessage());
            mLocalInstallListener.onError(e.getMessage().toString());
        }
        return false;
    }
}

感谢

文章链接找不到了,感谢作者提供的demo。

gitee.com/No.N/x5-tbs…