一、mui離線打包
工具:Android Studio、HBuilder、5+ SDK
1、下載5+ SDK(http://ask.dcloud.net.cn/article/103)
2、使用Android Studio創(chuàng)建一個新項目
3、復(fù)制SDK->libs->lib.5plus.base-release.aar文件到原生工程工程的app->libs目錄下

4、打開項目app目錄下的build.gradle文件,將aar包添加引用,加入如下代碼:
implementation fileTree(dir: 'libs', include: ['*.aar'])
5、修改工程的targetSdkVersion大于等于21

6、打開工程的Androidmanifest.xml文件,復(fù)制以下內(nèi)容替換該文件中原有application節(jié)點下的內(nèi)容
<application
android:name="io.dcloud.application.DCloudApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<!-- 啟動頁 -->
<activity
android:name="io.dcloud.PandoraEntry"
android:configChanges="orientation|keyboardHidden|screenSize|mcc|mnc|fontScale"
android:hardwareAccelerated="true"
android:screenOrientation="user"
android:theme="@style/TranslucentTheme"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
注:若自定義application,可采取繼承DCloudApplication,添加tools:replace="android:name"至application節(jié)點下,避免merge沖突。
7、復(fù)制SDK->assets->data目錄和目錄下的文件到工程的src->main->assets目錄下,新創(chuàng)建的工程默認(rèn)沒有assets目錄,可在與java同級目錄下創(chuàng)建assets目錄。

注: apps目錄下應(yīng)用資源的路徑為[appid].www, appid為應(yīng)用資源manifest.json文件中id節(jié)點的值,也就是mui項目manifest.json里的appid,如下圖:

8、將HBuilder里的代碼進(jìn)行本地打包,將應(yīng)用資源打包進(jìn)入Android項目的assets->apps對應(yīng)目錄下,HBuilder點擊發(fā)行->本地打包->生成本地打包App資源,將路徑選擇到apps即可。

9、修改assets->data->dcloud_control.xml文件的apps->app->appid屬性的值改為當(dāng)前應(yīng)用manifest.json文件id節(jié)點的值

運行項目,App便可進(jìn)入到mui的頁面,但是你會發(fā)現(xiàn)第一個頁面是這樣的

這是因為io.dcloud.PandoraEntry入口會先加載一個Splash頁面,暫時不知道如何去掉,我們需要將應(yīng)用的圖標(biāo)(文件名為icon.png)和啟動圖片(文件名為splash.png)放入drawable中,這樣Splash頁面就顯示你的splash圖片,如圖


二、插件開發(fā)
官方文檔一開始可能看的有點蛋疼,這里就寫個通俗點的例子,利用插件開發(fā)來進(jìn)行動態(tài)權(quán)限申請,也就是在mui利用插件到原生里進(jìn)行動態(tài)申請權(quán)限,然后將結(jié)果回調(diào)到mui這邊js里。
1、JS擴(kuò)展插件編寫
實現(xiàn)同步擴(kuò)展方法時,調(diào)用JS Plugin Bridge的window.plus.bridge.execSync()
方法,該方法可同步獲取Native插件返回的運行結(jié)果。
void plus.bridge.execSync( String service, String action, Array<String> args );
實現(xiàn)異步擴(kuò)展方法時,調(diào)用JS Plugin Bridge的plus.bridge.exec()方法,該方法會通知Native層插件執(zhí)行指定方法,運行結(jié)果會通過回調(diào)的方式通知JS層。
void plus.bridge.exec( String service, String action, Array<String> args );

2、實現(xiàn)擴(kuò)展插件類
(1) 創(chuàng)建一個繼承自StandardFeature的類
創(chuàng)建一個繼承自StandardFeature的類,實現(xiàn)第三方插件擴(kuò)展。
創(chuàng)建插件類需要引入的包
import io.dcloud.DHInterface.IWebview;
import io.dcloud.DHInterface.StandardFeature;
import io.dcloud.util.JSUtil;
(2) 實現(xiàn)擴(kuò)展方法
Native層擴(kuò)展插件的方法名需要和JS Plugin Bridge里windows.plus.bridge.exec()或windows.plus.bridge.execSync()方法的第二個傳入?yún)?shù)相同,否則無法調(diào)用到指定的方法。
public void PluginTestFunction(IWebview pWebview, JSONArray array)
(3) 返回值到j(luò)s層
同步執(zhí)行方法:
同步執(zhí)行方法在返回結(jié)果時可以直接將結(jié)果以return的形式返回給js層,返回的結(jié)果需要調(diào)用如下方法處理要返回的字符串。
JSUtil.wrapJsVar("Html5 Plus Plugin Hello1!",true);
異步執(zhí)行方法:
JSUtil.execCallback(pWebview, cbId, (which==AlertDialog.BUTTON_POSITIVE)?"ok":"cancel", JSUtil.OK, false, false);
3、關(guān)聯(lián)JS插件名和原生類
在Android原生工程的assets\data\dcloud_properties.xml文件中聲明插件類別名和Native層擴(kuò)展插件類的對應(yīng)關(guān)系
<properties>
<features>
...
<feature name="plugintest" value="com.kmvc.H5PlusPlugin.PGPlugintest"/>
</features>
<services>
...
<service name="plugintest" value="com.kmvc.H5PlusPlugin.PGPlugintest"></service>
</services>
</properties>
注:上面的value值便是擴(kuò)展插件類的路徑。
在應(yīng)用的manifest.json文件中還需要添加擴(kuò)展插件的應(yīng)用使用權(quán)限,permissions節(jié)點下添加如下:

4、使用實例
上面便是插件開發(fā)的核心步驟,下面舉個例子,就是上面說的動態(tài)權(quán)限申請
(1)、html調(diào)用上面寫好的js擴(kuò)展插件,js擴(kuò)展插件將調(diào)用原生那邊的插件類相應(yīng)方法
plus.plugintest.PluginTestFunction("PermissionCheck", "Plus", "AsyncFunction", "MultiArgument!", function(
result) {
if(result[0] == "MyPermissionOK") {
//getVersion();
} else if(result[0] == "MyPermissionDenied") {
mui.alert("關(guān)鍵權(quán)限必須打開,請進(jìn)入設(shè)置打開相關(guān)權(quán)限,否則將影響應(yīng)用正常使用!", "提示", function() {
//getVersion();
})
} else {
mui.alert("關(guān)鍵權(quán)限必須打開,請進(jìn)入設(shè)置打開相關(guān)權(quán)限,否則將影響應(yīng)用正常使用!", "提示", function() {
//getVersion();
})
}
}, function(result) {
mui.alert("權(quán)限申請失敗,請進(jìn)入設(shè)置打開相關(guān)權(quán)限,否則將影響應(yīng)用正常使用!", "提示", function() {
//getVersion();
})
});
(2)、原生插件類被調(diào)用之后獲取js傳過來的值,并跳轉(zhuǎn)到權(quán)限申請的原生頁面
public void PluginTestFunction(IWebview pWebview, JSONArray array) {
// 原生代碼中獲取JS層傳遞的參數(shù),
// 參數(shù)的獲取順序與JS層傳遞的順序一致
mWebview=pWebview;
CallBackID = array.optString(0);
String Method = array.optString(1);
JSONArray newArray = new JSONArray();
String par1 = array.optString(2);
String par2 = array.optString(3);
String par3 = array.optString(4);
String par14 = array.optString(5);
if("PermissionCheck".equals(Method)){
Intent intent = new Intent(mContext, XXX.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("CallBackID",CallBackID);
mContext.startActivity(intent);
}
}
(3)、權(quán)限申請的原生頁面獲取完權(quán)限申請結(jié)果后調(diào)用異步或同步方法回調(diào)到j(luò)s層,這里用的異步,如下
if(permission.granted){
// All permissions are granted !
JSUtil.execCallback(iWebview, callBackID, new JSONArray().put("MyPermissionOK"), JSUtil.OK, false);
finish();
}else if(permission.shouldShowRequestPermissionRationale){
// At least one denied permission without ask never again
JSUtil.execCallback(iWebview, callBackID, new JSONArray().put("MyPermissionDenied"), JSUtil.OK, false);
finish();
}else{
// At least one denied permission with ask never again
JSUtil.execCallback(iWebview, callBackID, new JSONArray().put("MyPermissionNeverAsked"), JSUtil.OK, false);
finish();
}
上面的代碼重點在JSUtil.execCallback方法,就是用來回調(diào)到j(luò)s層的,具體參數(shù)如下
iWebView:擴(kuò)展插件方法運行的窗口
callBackID:回調(diào)函數(shù)的唯一標(biāo)識
pMessage:回調(diào)函數(shù)的參數(shù)
pStatus:操作是否成功,成功則使用JSUtil.OK,否則使用錯誤代碼
isJson:回調(diào)函數(shù)參數(shù)是否為JSON數(shù)據(jù)
回調(diào)到j(luò)s層后便可根據(jù)返回的結(jié)果進(jìn)行處理,如上面第(1)步,我們根據(jù)權(quán)限申請的情況進(jìn)行相應(yīng)提示,并做了版本檢查更新操作。
最終效果:

ps:動態(tài)權(quán)限申請,需要targetSdkVersion大于等于23。