安卓第三方浏览器内核Crosswalk升级到77内核过程记录

一、背景介绍

libccy/noname项目是由水乎在2013年进行开发的一个Javascript游戏项目,其安卓端是使用了Cordova技术来进行文件读写等本地操作,由于其当时的手机Webview内核不尽人意,所以开发者水乎引入了第三方浏览器内核Crosswalk的17版本(chromium 46)。

目前在手机内置的Webview版本越来越高的情况下,对比当时引入的46内核,显得当时的Crosswalk内核极为卡顿,加载时间长,并且不能使用目前最基础的ES6语法。为了能使用更新的函数,我们引入了core.js,虽然解决了不能使用最新可polyfill函数的问题,但是也带来了一个不太能忍受的问题: 每次进入游戏都得等5秒以上!

二、内核的升级

1.所需环境

NodeJs:v10.24.1 (建议使用nvm)

Android Studio 2021.3.1 (需要有一定的安卓开发经验,我没有)

项目中Gradle 6.5

项目中Android Gradle Plugin Version 4.0

2.创建项目的步骤

下载全局cordova环境

css 复制代码
npm i cordova@8.1.0 -g

创建cordova项目

lua 复制代码
cordova create APP名称 APP包名

进入cordova项目,修改html文件为你需要运行的html文件(非必须)

bash 复制代码
cd APP名称

下载项目需要的其他cordova插件(非必须)

csharp 复制代码
cordova plugin add 插件名@版本号

下载项目需要的Crosswalk插件

csharp 复制代码
cordova plugin add cordova-plugin-crosswalk-webview-v3

下载他项目中我们需要的Crosswalk 77内核(aar文件),后续需要使用这个文件作为新内核使用

Crosswalk Native项目地址

添加安卓平台

sql 复制代码
cordova platform add android --save

使用Android Studio打开安卓项目: 项目名/platforms/android

安卓环境这块我也不太懂,但是需要保证platforms/android目录下有以下文件才能让项目调整Gradle然后正常运行:

配置镜像: 项目名/platforms/android/build.gradle

gradle 复制代码
buildscript {
    ext.kotlin_version = '1.3.50'
    repositories {
        maven{ url 'https://maven.aliyun.com/repository/public' }
        maven{ url 'https://maven.aliyun.com/repository/google' }
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.0.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        mavenCentral { url 'https://maven.aliyun.com/repository/public' }
        maven{ url 'https://maven.aliyun.com/repository/public' }
        maven{ url 'https://maven.aliyun.com/repository/google' }
        maven{ url 'https://maven.aliyun.com/repository/jcenter' }
        google()
    }

    //This replaces project.properties w.r.t. build settings
    project.ext {
      defaultBuildToolsVersion="29.0.2" //String
      defaultMinSdkVersion=24 //Integer - Minimum requirement is Android 5.1
      defaultTargetSdkVersion=29 //Integer - We ALWAYS target the latest by default
      defaultCompileSdkVersion=29 //Integer - We ALWAYS compile with the latest by default
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

将上面下载好的aar文件放入项目名/platforms/android/app/libs文件夹,然后修改项目名/platforms/android/cordova-plugin-crosswalk-webview-v3下的xxx-xwalk.gradle文件,然后执行gradle sync

gradle 复制代码
cdvPluginPostBuildExtras.add({
    ...
    android: {
        // 新增这个属性
        aaptOptions {
            noCompress 'dat', 'pak'
        }
    }
    ...
    dependencies: {
        // 第一个引入的包换成我们下载的aar文件,而不是请求Crosswalk官网下载53的内核
        implementation 'com.pakdata.xwalk.refactor:xwalk_core_lirary:77@aar'
        ...
    }
})

修改项目名/platforms/android/app/src/main/res/xml/config.xml文件,保证以下代码存在 注:关于--unlimited-storage的作用可以查看此议题

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<widget id="你的包名" version="App显示的版本号" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <!--  修改系统内核为Crosswalk内核  -->
    <preference name="webView" value="org.crosswalk.engine.XWalkWebViewEngine" />
    <preference default="17+" name="xwalkVersion" />
    <!--  默认值是--disable-pull-to-refresh-effect,加上--unlimited-storage是为了让indexedDB正常使用  -->
    <preference default="--disable-pull-to-refresh-effect --unlimited-storage" name="xwalkCommandLine" />
    <preference default="embedded" name="xwalkMode" />
    <preference default="false" name="xwalkMultipleApk" />
    <preference value="false" name="cdvBuildMultipleApks" />
    <!--  指定apk最低支持版本  -->
    <preference name="android-minSdkVersion" value="22"/>
    <!--  其他代码无需修改  -->
    ...
</widget>

从官方Crosswalk内核迁移到此内核,其数据会"丢失"。我和朋友研究出的迁移数据的代码如下(经过自己测试没有明显问题):

只需要把data下的app_xwalkcore/Default文件夹(旧版)重命名为app_xwalkcore/DefaultProfile文件夹(新版)即可

创建 项目名/platforms/android/app/src/main/java/你的包名/updateDataApplication.java

java 复制代码
package 你的包名;

import android.app.Application;
import android.util.Log;

import java.io.File;

public class updateDataApplication extends Application {
    private static final String TAG = "updateDataApplication";
    @Override
    public void onCreate() {
        super.onCreate();
        File dataPath =  getFilesDir().getParentFile();
        Log.e(TAG, dataPath.getAbsolutePath());
        File xwalkCore = new File(dataPath, "app_xwalkcore/");
        Log.e(TAG, String.valueOf(xwalkCore.exists()));
        Log.e(TAG, String.valueOf(xwalkCore.isDirectory()));

        File oldDataDirectory = new File(xwalkCore, "Default");
        Log.e(TAG, String.valueOf(oldDataDirectory.exists()));
        Log.e(TAG, String.valueOf(oldDataDirectory.isDirectory()));

        File newDataDirectory = new File(xwalkCore, "DefaultProfile");
        Log.e(TAG, String.valueOf(newDataDirectory.exists()));
        Log.e(TAG, String.valueOf(newDataDirectory.isDirectory()));

        if (oldDataDirectory.exists()) {
            if (newDataDirectory.exists()) {
                deleteFile(newDataDirectory);
            }
            // 重命名文件夹以同步数据
            Log.e(TAG, String.valueOf(
                    oldDataDirectory.renameTo(new File(xwalkCore, "DefaultProfile"))
            ));
        }
    }

    // 这个方法来自互联网
    private void deleteFile(File file) {
        if (file.exists()) {//判断文件是否存在
            if (file.isFile()) {//判断是否是文件
                file.delete();//删除文件
            } else if (file.isDirectory()) {//否则如果它是一个目录
                File[] files = file.listFiles();//声明目录下所有的文件 files[];
                for (int i = 0;i < files.length;i ++) {//遍历目录下所有的文件
                    this.deleteFile(files[i]);//把每个文件用这个方法进行迭代
                }
                file.delete();//删除文件夹
            }
        } else {
            Log.e(TAG,"所删除的文件不存在");
        }
    }
}

然后修改项目名/platforms/android/app/src/main/AndroidManifest.xml,应用你的updateDataApplication类,以及添加必要的安卓权限

xml 复制代码
<?xml version='1.0' encoding='utf-8'?>
<manifest xmlns:tools="http://schemas.android.com/tools"
    android:hardwareAccelerated="true" android:versionCode="实际的版本号代码" android:versionName="显示的版本号" package="你的包名" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
    <!--  系统权限  -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!--  应用你的updateDataApplication类  -->
    <application android:name=".updateDataApplication" android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:usesCleartextTraffic="true" tools:targetApi="m">
        <!--  activity按你的实际需求来  -->
        <activity
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
            android:label="@string/activity_name"
            android:launchMode="singleTop"
            android:name="MainActivity"
            android:screenOrientation="sensorLandscape"
            android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
            android:windowSoftInputMode="adjustResize"
            android:exported="true">
            <intent-filter android:label="@string/launcher_name">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

最后,使用Android Studio自带的打包功能进行打包,或者进行debug测试

成果截图:

三、后续问题以及解决

1.运行成功后,发现元素获得焦点后会有橙色的框框,通过远程调试发现用户代理样式表中有以下样式规则:

解决办法: 在html里加一个:focus { outline: none; }样式即可

  1. file协议下,使用import语法错误,提示TypeError: Failed to fetch dynamically imported module: xxx

解决办法: 修改 项目名/platforms/android/app/src/main/java/org/crosswalk/engine/XWalkCordovaResourceClient.java

java 复制代码
import android.util.Log;

// 在这个方法下面添加新的方法
@Override
public WebResourceResponse shouldInterceptLoadRequest(XWalkView view, String url) {
...
} 

// 新增方法
@Override
public XWalkWebResourceResponse shouldInterceptLoadRequest(XWalkView view, XWalkWebResourceRequest request) {
        String url = request.getUrl().toString();
        String method = request.getMethod();
        Map<String, String> headers = request.getRequestHeaders();
        Log.e("Request", method + "  " + url + "  " + headers);

        if (url.startsWith("file://") && !url.contains("/app_webview/")&& !url.contains("/app_xwalkcore/")) {
            // 是否是模块请求
            if (headers != null
                    && headers.containsKey("Origin")
                    && Objects.equals(headers.get("Origin"), "file://")
                    && Objects.equals(headers.get("Sec-Fetch-Mode"), "cors")) {
                try {
                    URL Url = new URL(url);
                    URLConnection connection = Url.openConnection();
                    InputStream data = Url.openStream();
                    // 手动返回数据
                    return createXWalkWebResourceResponse(connection.getContentType(), "utf-8", data);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
        // 返回null是让浏览器自己处理
        return null;
    }
相关推荐
雨白8 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹9 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空11 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭12 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日13 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安13 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑13 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟17 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡18 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0018 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体