這是個人在學習weex中遇到的坑,以及解決方法,歡迎共同交流
weex簡介
js作爲連接原生控件與視圖層紐帶 ,代替了以往使用的java、oc、swift直接調用原生控件 、這樣生成的ui層依舊是原生的、和 html毫無關係,至於那些div,image只不過是名字和html標籤一樣的組件而已,也沒有了dome對象的存在,因爲實際 開發的環境不是瀏覽器,而是基於原生,
初始化:
- 1,初始環境:安裝node.js以及mpm
- 2,npm install weex-toolkit -g
全局安裝weex-tooklkit
在命令環境註冊一個weex命令
- 3,進入到需要部署的文件目錄
weex create awesome-app
命令執行完成,當前名錄的awesome-app文件夾裏就存在一個空Weex Vue.js項目
開發:
- 進入創建的文件夾,安裝依賴,
- cd awesome-app
- npm install
- npm start
- 工具會 啓動一個本地的web服務,監聽8081端口。打開http://localhost:8081查看頁面在web下的渲染效果。
- 源代碼在src/目錄中,你可以像一個普通Vue.js項目一樣進行開發
- 可以打開http://localhost:8081/preview.html開啓預覽頁面,他會把web端頁面放在一個iframe中渲染,右側二維碼可以用Weex palyround app掃描預覽;
運行和編譯
安裝weexpack:
初始環境:安裝node.js以及mpm
$ cnpm install -g weexpack
或者 在 clone 的 weexpack 根目錄下執行
$ cnpm install
創建 weexpack工程
weexpack create appNmae (工程名)
cd appName
npm install 初始化依賴
安裝應用模板 生成 android 或者 ios 工程
- android模板
weexpack platform add android
執行完成後會在platforms文件夾下生成android文件目錄
- ios工程模板
weexpack platform add ios
執行完成後會在platforms文件夾下生成ios文件目錄
weex platform add android
開發完成之後weex run android
打包android工程
然後用android stodio 打開工程編譯
坑1:
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.equals('app-debug.apk')) {
def fileName = outputFile.name.replace("app-debug.apk", "weex-app.apk")
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
替換爲
applicationVariants.all { variant ->
variant.outputs.all { output ->
def fileName = "${variant.versionName}_release.apk"
def outFile = output.outputFile
// if (outputFile != null && outputFile.name.equals('app-debug.apk')) {
// def fileName = outputFile.name.replace("app-debug.apk", "weex-app.apk")
// outputoutputFile = fileName
// }
if (outFile != null && outFile.name.endsWith('.apk')) {
outputFileName = fileName // output.outputFile 改爲 outputFileName
}
}
}
坑2
Error:Execution failed for task ':uikit:javaPreCompileDebug'. > Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration. - compiler-4.0.0-RC0.jar (com.github.bumptech.glide:compiler:4.0.0-RC0) - auto-service-1.0-rc3.jar (com.google.auto.service:auto-service:1.0-rc3) Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future. See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.
解決方法:
在app的build.gradle中添加如下部分:
android { compileSdkVersion 26 buildToolsVersion '26.0.2' defaultConfig { applicationId "com.example.app" minSdkVersion 15 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //添加部分 javaCompileOptions { annotationProcessorOptions { includeCompileClasspath true } } } }
坑三:不顯示本地文件
weex不顯示本地文件,
可以直接寫絕對路徑 ip+端口號/src/存放圖片文件夾/圖片名稱
然後在安卓和ios分別的解決方法是:
Android 的實現方法
圖片存儲的目錄
res/drawable-hdpi
下面會提到,爲何要存儲到這裏
引用方法
<img src="local:///test" style="width: 300; height: 300;">
不需要加圖片的文件名後綴
注意:是三個斜槓,不是兩個,否則會報錯
E/weex: Local src format is invalid.
如果你是在google play上上架。建議mdpi,hdpi,xhdpi,xxhdpi每一種都放一套(ldpi就算了,基本看不到),因爲google play會根據不同的手機density來打不同的apk包(舉個栗子,如果是hdpi的機器,下載下來的就只有hdpi的資源) 如果是在國內的市場話。建議只放一套(h或者xhpdi),因爲國內市場是沒有上面那種機制的,放多套資源會導致安裝包變得很大。 此外: Android在沒有找到相應dpi的圖片時,會用其他density的圖片進行縮放處理。因此會損失一些性能和內存(作爲縮放的buffer使用)
參考 Android 開發中 drawable 有必要放多套分辨率的圖片資源嗎?
iOS 的實現方法
圖片存儲目錄
main bundle
引用方法
<img src="local://test.png" style="width: 300; height: 300;">
我這裏直接報 domain error, 而不是 no resource found 說明並沒有走最新的 SDK 代碼流程。
最終在官方文檔 Path (英) | Weex 的相對路徑部分找到了解決方法。
即使用相對路徑即可!
xcode 最傻逼的地方是,需要手動將圖片拖動到項目的 resource 目錄。 需要自動添加的方案!!!
先手動在 resource 目錄新建一個 images 目錄,然後,不斷往這個目錄裏新增圖片文件即可。
同步解決(感覺不夠完美)
圖片的同步
npm run copy:xx 解決
package.json
"scripts": { "build": "webpack", "dev": "npm run build && webpack --watch", "copy:android": "mkdir -p platforms/android/app/src/main/assets/dist/; cp dist/index.weex.js platforms/android/app/src/main/assets/dist/index.js; cp src/images/*.* platforms/android/app/src/main/res/drawable-hdpi/", "copy:ios": "mkdir -p platforms/ios/bundlejs/ && cp dist/index.weex.js platforms/ios/bundlejs/index.js && cp src/images/*.* platforms/ios/images/", "copy": "npm run copy:android && npm run copy:ios", "serve": "serve -p 1337", "test": "echo \"Error: no test specified\" && exit 1" },
實現代碼
src/mixins/index.js
// 獲取圖片在三端上不同的路徑 // e.g. 圖片文件名是 test.jpg, 轉換得到的圖片地址爲 // - H5 : http: //localhost:1337/src/images/test.jpg // - Android : local:///test // - iOS : ../images/test.jpg get_img_path(img_name) { let platform = weex.config.env.platform let img_path = '' if (platform == 'Web') { img_path = `http://localhost:1337/src/images/${img_name}` } else if (platform == 'android') { // android 不需要後綴 img_name = img_name.substr(0, img_name.lastIndexOf('.')); img_path = `local:///${img_name}` } else { img_path = `../images/${img_name}` } return img_path }
使用方法
<image style="width: 120px; height: 120px;" :src="get_img_path('test.png')"></image>
坑4:
頁面跳轉問題
https://blog.csdn.net/blog_lee/article/details/79820130詳情可參考
新增uril.js,在需要的頁面調用代碼如下
export function getEntryUrl(name) {
//判斷當前的環境,適配web端
if (weex.config.env.platform === "Web") {
// return './' + name + '.html'
} else {
let arr = weex.config.bundleUrl.split('/');
arr.pop();
arr.push(name + '.js');
console.log(arr.join('/'))
return "local://" + arr.join('/');
}
}
使用方法:
navigator.push({
// url: "./detail.html",
url: getEntryUrl("login"),
animated: "true"
})
Android相關代碼
- 創建一個Activity,如下圖所示位置以及代碼
package com.weex.app.util; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import com.taobao.weex.IWXRenderListener; import com.taobao.weex.WXSDKInstance; import com.taobao.weex.common.WXRenderStrategy; import com.taobao.weex.devtools.common.LogUtil; import com.weex.app.R; import java.util.HashMap; import java.util.Map; /** * Created by lee on 29/03/2018. */ public class Network extends AppCompatActivity implements IWXRenderListener { private WXSDKInstance mWXSDKInstance; private FrameLayout mContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); mContainer = (FrameLayout) findViewById(R.id.container); mWXSDKInstance = new WXSDKInstance(this); mWXSDKInstance.registerRenderListener(this); String RenderPageUrl = ""; if (getIntent().getData() != null) { String navUrl = getIntent().getData().toString(); if (null != navUrl) { LogUtil.e(navUrl); RenderPageUrl = navUrl; } else { LogUtil.e("a is null"); } } else { LogUtil.e("get data is null"); } Map<String, Object> options = new HashMap<>(); options.put(WXSDKInstance.BUNDLE_URL, RenderPageUrl); mWXSDKInstance.renderByUrl("WXSample", RenderPageUrl, options, null, WXRenderStrategy.APPEND_ONCE); } @Override protected void onStart() { super.onStart(); if (mWXSDKInstance != null) { mWXSDKInstance.onActivityStart(); } } @Override protected void onResume() { super.onResume(); if (mWXSDKInstance != null) { mWXSDKInstance.onActivityResume(); } } @Override protected void onPause() { super.onPause(); if (mWXSDKInstance != null) { mWXSDKInstance.onActivityPause(); } } @Override protected void onStop() { super.onStop(); if (mWXSDKInstance != null) { mWXSDKInstance.onActivityStop(); } } @Override protected void onDestroy() { super.onDestroy(); if (mWXSDKInstance != null) { mWXSDKInstance.onActivityDestroy(); } } @Override public void onViewCreated(WXSDKInstance instance, View view) { if (view.getParent() != null) { ((ViewGroup) view.getParent()).removeView(view); } mContainer.addView(view); } @Override public void onRenderSuccess(WXSDKInstance instance, int width, int height) { } @Override public void onRefreshSuccess(WXSDKInstance instance, int width, int height) { } @Override public void onException(WXSDKInstance instance, String errCode, String msg) {
- 創建Activity佈局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_network" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"></FrameLayout> </RelativeLayout>
- 修改manifest.xml-添加攔截器
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.weex.app"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/> <uses-feature android:name="android.hardware.camera"/> <uses-feature android:name="android.hardware.camera.autofocus"/> <application android:name="com.weex.app.WXApplication" android:allowBackup="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" tools:overrideLibrary="com.taobao.android.dexposed" tools:replace="android:allowBackup"> <activity android:name="com.weex.app.SplashActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:label="@string/app_name" android:screenOrientation="portrait" android:theme="@style/FullscreenTheme"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name="com.weex.app.WXPageActivity" android:label="@string/app_name" android:screenOrientation="portrait"> </activity> <activity android:name=".util.Network"> <intent-filter> <action android:name="com.taobao.android.intent.action.WEEX" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="com.taobao.android.intent.category.WEEX" /> <action android:name="android.intent.action.VIEW" /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:scheme="file" /> <data android:scheme="network" /> </intent-filter> </activity> <activity android:name="com.journeyapps.barcodescanner.CaptureActivity" android:screenOrientation="portrait" tools:replace="screenOrientation"/> </application> </manifest>
坑5
android7 權限問題:
https://blog.csdn.net/jupiterxx/article/details/80026909
你的項目就可以用 weex run android運行在安卓手機上了...
網上好多說需要找到本地資源文件夾下的地址即可跳轉.. 在android中.. 確實發現assets文件夾下有這些界面的js文件..
只要用 file://assets/dist/在安卓中找到這個文件跳轉就可以了.. 然後再次發現是無效的.. 但是發現跳轉http和https在手機上是有效的.. 那麼也就是說隱式調用沒有攔截到這file這個請求..
但是明明在android項目的manifast裏是已經在攔截file的.. 最後發現確實file是攔截不到的.. 其他什麼關鍵字都可以.. 那麼怎麼辦呢.. 最後我只能在地址前面加上別的關鍵字local 但是讓隱式攔截local關鍵字.. 最後再activity裏再把local給去掉 用file地址去渲染..
最終獲取三端對應跳轉地址的方法 (注意安卓中前面添加了local是爲了給攔截)
- getJumpBaseUrl(toUrl) {
- var bundleUrl = weex.config.bundleUrl;
- var isnav = true
- bundleUrl = new String(bundleUrl);
- var nativeBase;
- var native;
- var isAndroidAssets = bundleUrl.indexOf('file://assets/') >= 0;
- var isiOSAssets = bundleUrl.indexOf('file:///') >= 0 && bundleUrl.indexOf('WeexDemo.app') > 0;
- if (isAndroidAssets) {
- nativeBase = "local://" + 'file://assets/dist/';
- native = nativeBase + toUrl + ".js";
- } else if (isiOSAssets) {
- nativeBase = bundleUrl.substring(0, bundleUrl.lastIndexOf('/') + 1);
- native = nativeBase + toUrl + ".js";
- } else {
- var host = 'localhost:8081';
- var matches = /\/\/([^\/]+?)\//.exec(bundleUrl);
- if (matches && matches.length >= 2) {
- host = matches[1];
- }
- //此處需注意一下,tabbar 用的直接是jsbundle 的路徑,但是navigator是直接跳轉到新頁面上的.
- if (typeof window === 'object') {
- nativeBase = 'http://' + host + '/';
- } else {
- nativeBase = 'http://' + host + '/';
- }
- native = nativeBase + toUrl + ".html";
- }
- return native;
- }
android manifest 中攔截local
- <activity
- android:name="com.weex.app.WXPageActivity"
- android:label="@string/app_name"
- android:screenOrientation="portrait"
- >
- <intent-filter>
- <action android:name="android.intent.action.VIEW"/>
- <action android:name="com.alibaba.weex.protocol.openurl"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <category android:name="com.taobao.android.intent.category.WEEX"/>
- <data android:scheme="http"/>
- <data android:scheme="https"/>
- <data android:scheme="local"/>
- </intent-filter>
- </activity>
android java code中把local頭給去掉 拿file地址去渲染
把local關鍵字給替換掉.. 然後其他的和原來操作一樣