目前在尝试使用weex,但是在搭建基础的最小化项目的时候,官方文档描述的相当佛系,导致搭建出来的项目没办法正常运行。
下面我们探讨一下,使用Android Studio 3.5.2
新建一个项目,实现最小化接入weex 0.28.0
实践过程。
官方文档要求在项目的build.gradle
中增加如下内容:
1 2 |
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
的头部增加这个脚本文件的引用:
1 |
apply from: 'https://raw.githubusercontent.com/apache/incubator-weex/release/0.28/android/sdk/buildSrc/download_jsc.gradle' |
如果下载不成功,也可从本站下载
1 |
apply from: 'https://www.mobibrw.com/wp-content/uploads/2019/11/download_jsc.gradle' |
完成后的build.gradle
中完整内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
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
,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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
内容展现代码部分了,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
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 这个文件里面的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
// { "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 /***/ } /******/ ]); |
你好,请问你这个远程依赖下载,如果依赖源码你知道具体的工作步骤吗?方便的话提供下源码,我现在怎么也编译不通过
源代码在最下面是一个可以正常使用的例子,参考这个例子。至于源代码开始编译,正常情况下,开源项目都要折腾许久才能编译通过,另外淘宝的项目,一般依赖的NDK在16左右,不要升级到新版本的NDK
weex 在0.28版本之前直接依赖Android sdk 源码就可以直接使用, 但是从0.28版本起,整体架构包名动态库改变,现在我想直接依赖0.28源码,但是都是编译不通过。根据你提供的信息,playgroud 案例我已经成功运行,但是项目依赖的是sdk legacyRelease版本,而且是已NDK的方式编译依赖,现在我想直接依赖修改包名org.apache 版本的SDK 源码,请问需要哪些动态库,需要准备哪些工作,求指点,谢谢!
检查编译出来的Apk即可
//apply from: 'https://www.mobibrw.com/wp-content/uploads/2019/11/download_jsc.gradle'
您好,此下载地址可以使用,但是否稳定?因为这边下载官网的地址失败。现在用于项目是否稳定?
这个是我个人的网站,暂时还算稳定
谢谢您的回复,请问您有解决无法正常下载的方法吗?希望可以给一个建议。
一般都是翻墙出去的,之所以我自己网站上备份一份,就是因为国外网站访问经常出问题。公司一般都是自己搭建一套镜像服务器来解决这种问题的。
感谢。其实这个apply 最终是生成了相关的so文件,是不是可以说生成相应的jar包后就可以不使用apply from了?
原理上是的,但是每次编译都依赖这个过程,否则可能会报告编译异常的,尽管确实是编译之后不需要了。但是这总是一个步骤,如果缺少了,可能最后生产的包出现问题。
您好,完全按照你的操作来的,但是控制台报错
Didn't find class "com.taobao.windmill.bundle.bridge.WeexBridge"
请问下什么原因呢
明显是版本太低了,新版本的从com.taobao域修改成了org.apache域了,你代码的某些库依旧按照老域来调用
使用weex 28 debug出不来,有改动还是怎么样哇?
是不是文件下载失败了?看看错误提示
你好,我直接依赖0.28sdk_legacy 版本 ,但是总是提示各种动态库so找不到,这个问题是什么问题
由于weex 0.28.0的调整,以前版本自动引入的facebook提供的JS引擎js-android,现在被修改为需要手工引入,但是文档没有清晰的指出这个问题,导致运行的时候,会由于找不到libjsc.so而导致WXSDKEngine初始化失败。download_jsc.gradle 是否引入?
download_jsc.gradle 引入了,并且jni下面也有libjsc.so,也引入了implementation 'org.webkit:android-jsc:r174650' 但是还是会提示找不到libc++_shared.so还有weexcore.so
couldn't find "libweexcore.so",这个so包也没找到哪里能下载到【捂脸】
0.28版本 调用 mWXSDKInstance.resetDeviceDisplayOfPage();
mWXSDKInstance.reloadPageLayout(); 这两个方法之后页面确实重新刷新了,但是以wx为单位的部分显示不正常,比如marginTop 设置的-100wx,第一次打开正常,调用上面的方法刷新,-100wx 变大了貌似计算出来的距离成了原来的两倍,你有没有遇到这个问题
这个就不清楚了
感谢啊 通过你的方法 我0.28版本集成成功了。之前不行是因为各种so包没有正确放到jni包下面,我也不知道为什么,我是从项目build文件夹下面找到的,直接拷贝过去的。
但是对于0.28的api我有点问题,因为我现在要处理的情况是同一个页面在页面尺寸变化的情况下,比如屏幕宽度从1000变成800 然后我调用0.28的api mWXSDKInstance.resetDeviceDisplayOfPage();确实刷新了页面,但是偶尔又会失败,不确定是为什么(我们是在适配华为的平行世界功能,双界面)
这个去GitHub或者官网上去问一下吧,他们有专门的答疑人员的,不过貌似会比较耗时
可以试试在浏览器中访问一下这个地址,如果访问不到,就是没有下载到,另外这个地址是http的,新版本的Android已经不允许访问http,只能访问https 这个需要在代码中设置才可以
可以试试这个文件的内容放到assets里面访问,这个文件里的内容在文章的最下面。
谢谢