Android Studio 3.5.2最小化接入weex 0.28.0实践

目前在尝试使用weex,但是在搭建基础的最小化项目的时候,官方文档描述的相当佛系,导致搭建出来的项目没办法正常运行。

下面我们探讨一下,使用`Android Studio 3.5.2`新建一个项目,实现最小化接入`weex 0.28.0`实践过程。

官方文档要求在项目的`build.gradle` 中增加如下内容:

implementation 'org.apache.weex:sdk:0.28.0@aar'
implementation 'com.alibaba:fastjson:1.2.62'

但是实际上,由于`weex 0.28.0`的调整,以前版本自动引入的`facebook`提供的`JS`引擎js-android,现在被修改为需要手工引入,但是文档没有清晰的指出这个问题,导致运行的时候,会由于找不到`libjsc.so`而导致`WXSDKEngine`初始化失败。

官方提供了一个`download_jsc.gradle`的脚本解决这个问题(这个脚本的功能仅仅是下载`libjsc.so` ),需要在项目的 `build.gradle` 的头部增加这个脚本文件的引用:

apply from: 'https://raw.githubusercontent.com/apache/incubator-weex/release/0.28/android/sdk/buildSrc/download_jsc.gradle'

如果下载不成功,也可从本站下载

apply from: 'https://www.mobibrw.com/wp-content/uploads/2019/11/download_jsc.gradle'

完成后的`build.gradle`中完整内容如下:

apply plugin: 'com.android.application'
apply from: 'https://raw.githubusercontent.com/apache/incubator-weex/release/0.28/android/sdk/buildSrc/download_jsc.gradle'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.mobibrw.weex"
        minSdkVersion 22
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        ndk {
            abiFilters "armeabi","armeabi-v7a", "arm64-v8a", "x86"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.0.0'
    implementation 'org.apache.weex:sdk:0.28.0@aar'
    implementation 'com.alibaba:fastjson:1.2.62'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

接下来,就是具体的代码部分了,如下,需要自定义一个`Application`类,在`Application`的初始化部分初始化`WXSDKEngine`,代码如下:

package com.mobibrw.weex;

import android.app.Application;
import org.apache.weex.InitConfig;
import org.apache.weex.WXSDKEngine;

public class WeexApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        final InitConfig config = new InitConfig.Builder().build();
        /**
         * 底层的初始化是异步执行的,尤其是初始化JS引擎部分的代码(WXBridgeManager),是相当耗时的
         * 因此,在调用完初始化之后,Activity第一次调用的时候,一定要增加是否已经初始化完成的判断
         * 如果没有完成初始化,适当的增加延迟等待的代码
         **/
        WXSDKEngine.initialize(this, config);
    }

}

接下来,就是具体的`Activity`内容展现代码部分了,代码如下:

package com.mobibrw.weex;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import org.apache.weex.IWXRenderListener;
import org.apache.weex.WXSDKEngine;
import org.apache.weex.WXSDKInstance;
import org.apache.weex.common.WXRenderStrategy;

public class MainActivity extends AppCompatActivity implements IWXRenderListener {

    private WXSDKInstance wXSDKInstance;

    private static final String TAG = "WXSampleTAG";

    private void loadPages() {
        /**
         * bundleUrl source http://dotwe.org/vue/38e202c16bdfefbdb88a8754f975454c
         */
        String pageName = "WXSample";
        String bundleUrl = "http://dotwe.org/raw/dist/38e202c16bdfefbdb88a8754f975454c.bundle.wx";
        wXSDKInstance.renderByUrl(pageName, bundleUrl, null, null, WXRenderStrategy.APPEND_ASYNC);
    }

    private void asyncLoadPages(final View view) {
        /**
         * 此处一定要判断WXSDKEngine是否已经成功初始化了,由于WXSDKEngine底层初始化的库非常多
         * 导致整个的初始化非常的耗时,并且这个初始化是异步执行的,尤其是初始化JS引擎部分的代码(WXBridgeManager)。
         * 因此有非常大的概率导致当第一次使用Week的API的时候,底层还没有完成初始化
         * 导致出现错信息 "degradeToH5|createInstance fail|wx_create_instance_error isJSFrameworkInit==false reInitCount == 1"
         * 这段耗时可以通过在程序启动的时候增加启动等待页面来人性化的忽略这部分耗时。
         **/
        if(!WXSDKEngine.isInitialized()) {
            view.postDelayed(new Runnable() {
                @Override
                public void run() {
                    asyncLoadPages(view);
                }
            }, 1);
        } else {
            loadPages();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final View view = findViewById(R.id.activity_main);

        wXSDKInstance = new WXSDKInstance(this);
        wXSDKInstance.registerRenderListener(this);
        asyncLoadPages(view);
    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }

    @Override
    public void onViewCreated(WXSDKInstance instance, View view) {
        setContentView(view);
    }

    @Override
    public void onRenderSuccess(WXSDKInstance instance, int width, int height) {
        Log.i(TAG, "onRenderSuccess");
    }

    @Override
    public void onRefreshSuccess(WXSDKInstance instance, int width, int height) {
        Log.i(TAG, "onRefreshSuccess");
    }

    @Override
    public void onException(WXSDKInstance instance, String errCode, String msg) {
        Log.e(TAG, "onException:" + msg);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(wXSDKInstance!=null){
            wXSDKInstance.onActivityResume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if(wXSDKInstance!=null){
            wXSDKInstance.onActivityPause();
        }
    }
    @Override
    protected void onStop() {
        super.onStop();
        if(wXSDKInstance!=null){
            wXSDKInstance.onActivityStop();
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(wXSDKInstance!=null){
            wXSDKInstance.onActivityDestroy();
        }
    }
}

需要注意的是`WXSDKEngine`是异步初始化的,导致在首次调用的时候,可能会因为没有正常初始化而出现异常,因此需要等待初始化完成。

具体的例子项目在这里下载 Weex

鉴于开源项目经常性找不到文件,因此记录下来 http://dotwe.org/raw/dist/38e202c16bdfefbdb88a8754f975454c.bundle.wx 这个文件里面的内容:

// { "framework": "Vue" }

/******/
(function(modules) { // webpackBootstrap
    /******/ // The module cache
    /******/
    var installedModules = {};

    /******/ // The require function
    /******/
    function __webpack_require__(moduleId) {

        /******/ // Check if module is in cache
        /******/
        if (installedModules[moduleId])
        /******/
            return installedModules[moduleId].exports;

        /******/ // Create a new module (and put it into the cache)
        /******/
        var module = installedModules[moduleId] = {
            /******/
            exports: {},
            /******/
            id: moduleId,
            /******/
            loaded: false
                /******/
        };

        /******/ // Execute the module function
        /******/
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

        /******/ // Flag the module as loaded
        /******/
        module.loaded = true;

        /******/ // Return the exports of the module
        /******/
        return module.exports;
        /******/
    }


    /******/ // expose the modules object (__webpack_modules__)
    /******/
    __webpack_require__.m = modules;

    /******/ // expose the module cache
    /******/
    __webpack_require__.c = installedModules;

    /******/ // __webpack_public_path__
    /******/
    __webpack_require__.p = "";

    /******/ // Load entry module and return exports
    /******/
    return __webpack_require__(0);
    /******/
})
/************************************************************************/
/******/
([
    /* 0 */
    /***/
    function(module, exports, __webpack_require__) {

        'use strict';

        var _e202c16bdfefbdb88a8754f975454c = __webpack_require__(1);

        var _e202c16bdfefbdb88a8754f975454c2 = _interopRequireDefault(_e202c16bdfefbdb88a8754f975454c);

        function _interopRequireDefault(obj) {
            return obj && obj.__esModule ? obj : {
                default: obj
            };
        }

        _e202c16bdfefbdb88a8754f975454c2.default.el = '#root';
        new Vue(_e202c16bdfefbdb88a8754f975454c2.default);

        /***/
    },
    /* 1 */
    /***/
    function(module, exports, __webpack_require__) {

        var __vue_exports__, __vue_options__
        var __vue_styles__ = []

        /* styles */
        __vue_styles__.push(__webpack_require__(2))

        /* script */
        __vue_exports__ = __webpack_require__(3)

        /* template */
        var __vue_template__ = __webpack_require__(4)
        __vue_options__ = __vue_exports__ = __vue_exports__ || {}
        if (
            typeof __vue_exports__.default === "object" ||
            typeof __vue_exports__.default === "function"
        ) {
            if (Object.keys(__vue_exports__).some(function(key) {
                    return key !== "default" && key !== "__esModule"
                })) {
                console.error("named exports are not supported in *.vue files.")
            }
            __vue_options__ = __vue_exports__ = __vue_exports__.default
        }
        if (typeof __vue_options__ === "function") {
            __vue_options__ = __vue_options__.options
        }
        __vue_options__.__file = "/usr/src/app/raw/38e202c16bdfefbdb88a8754f975454c.vue"
        __vue_options__.render = __vue_template__.render
        __vue_options__.staticRenderFns = __vue_template__.staticRenderFns
        __vue_options__._scopeId = "data-v-02e1e786"
        __vue_options__.style = __vue_options__.style || {}
        __vue_styles__.forEach(function(module) {
            for (var name in module) {
                __vue_options__.style[name] = module[name]
            }
        })
        if (typeof __register_static_styles__ === "function") {
            __register_static_styles__(__vue_options__._scopeId, __vue_styles__)
        }

        module.exports = __vue_exports__


        /***/
    },
    /* 2 */
    /***/
    function(module, exports) {

        module.exports = {
            "text": {
                "fontSize": 50
            }
        }

        /***/
    },
    /* 3 */
    /***/
    function(module, exports) {

        'use strict';

        Object.defineProperty(exports, "__esModule", {
            value: true
        });
        //
        //
        //
        //
        //
        //
        //
        //
        //
        //

        exports.default = {
            data: function data() {
                return {
                    text: 'Hello World.'
                };
            }
        };

        /***/
    },
    /* 4 */
    /***/
    function(module, exports) {

        module.exports = {
            render: function() {
                var _vm = this;
                var _h = _vm.$createElement;
                var _c = _vm._self._c || _h;
                return _c('div', [_c('text', {
                    staticClass: ["text"]
                }, [_vm._v(_vm._s(_vm.text))])])
            },
            staticRenderFns: []
        }
        module.exports.render._withStripped = true

        /***/
    }
    /******/
]);

参考链接


发布者

《Android Studio 3.5.2最小化接入weex 0.28.0实践》上有27条评论

  1. 你好,请问你这个远程依赖下载,如果依赖源码你知道具体的工作步骤吗?方便的话提供下源码,我现在怎么也编译不通过

    1. 源代码在最下面是一个可以正常使用的例子,参考这个例子。至于源代码开始编译,正常情况下,开源项目都要折腾许久才能编译通过,另外淘宝的项目,一般依赖的NDK在16左右,不要升级到新版本的NDK

      1. weex 在0.28版本之前直接依赖Android sdk 源码就可以直接使用, 但是从0.28版本起,整体架构包名动态库改变,现在我想直接依赖0.28源码,但是都是编译不通过。根据你提供的信息,playgroud 案例我已经成功运行,但是项目依赖的是sdk legacyRelease版本,而且是已NDK的方式编译依赖,现在我想直接依赖修改包名org.apache 版本的SDK 源码,请问需要哪些动态库,需要准备哪些工作,求指点,谢谢!

  2. //apply from: 'https://www.mobibrw.com/wp-content/uploads/2019/11/download_jsc.gradle'
    您好,此下载地址可以使用,但是否稳定?因为这边下载官网的地址失败。现在用于项目是否稳定?

        1. 一般都是翻墙出去的,之所以我自己网站上备份一份,就是因为国外网站访问经常出问题。公司一般都是自己搭建一套镜像服务器来解决这种问题的。

          1. 感谢。其实这个apply 最终是生成了相关的so文件,是不是可以说生成相应的jar包后就可以不使用apply from了?

          2. 原理上是的,但是每次编译都依赖这个过程,否则可能会报告编译异常的,尽管确实是编译之后不需要了。但是这总是一个步骤,如果缺少了,可能最后生产的包出现问题。

  3. 您好,完全按照你的操作来的,但是控制台报错
    Didn't find class "com.taobao.windmill.bundle.bridge.WeexBridge"
    请问下什么原因呢

    1. 由于weex 0.28.0的调整,以前版本自动引入的facebook提供的JS引擎js-android,现在被修改为需要手工引入,但是文档没有清晰的指出这个问题,导致运行的时候,会由于找不到libjsc.so而导致WXSDKEngine初始化失败。download_jsc.gradle 是否引入?

  4. download_jsc.gradle 引入了,并且jni下面也有libjsc.so,也引入了implementation 'org.webkit:android-jsc:r174650' 但是还是会提示找不到libc++_shared.so还有weexcore.so

  5. 0.28版本 调用 mWXSDKInstance.resetDeviceDisplayOfPage();
    mWXSDKInstance.reloadPageLayout(); 这两个方法之后页面确实重新刷新了,但是以wx为单位的部分显示不正常,比如marginTop 设置的-100wx,第一次打开正常,调用上面的方法刷新,-100wx 变大了貌似计算出来的距离成了原来的两倍,你有没有遇到这个问题

  6. 感谢啊 通过你的方法 我0.28版本集成成功了。之前不行是因为各种so包没有正确放到jni包下面,我也不知道为什么,我是从项目build文件夹下面找到的,直接拷贝过去的。
    但是对于0.28的api我有点问题,因为我现在要处理的情况是同一个页面在页面尺寸变化的情况下,比如屏幕宽度从1000变成800 然后我调用0.28的api mWXSDKInstance.resetDeviceDisplayOfPage();确实刷新了页面,但是偶尔又会失败,不确定是为什么(我们是在适配华为的平行世界功能,双界面)

    1. 例子中使用的是 String bundleUrl = "http://dotwe.org/raw/dist/38e202c16bdfefbdb88a8754f975454c.bundle.wx"; 这个地址经常访问不到,因此才会白屏幕,

      可以试试在浏览器中访问一下这个地址,如果访问不到,就是没有下载到,另外这个地址是http的,新版本的Android已经不允许访问http,只能访问https 这个需要在代码中设置才可以

      可以试试这个文件的内容放到assets里面访问,这个文件里的内容在文章的最下面。

回复 默默 取消回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注