MUI离线打包及插件开发

一、mui离线打包

工具:Android Studio、HBuilder、5+ SDK

1、下载5+ SDK(http://ask.dcloud.net.cn/article/103)
2、使用Android Studio创建一个新项目
3、复制SDK->libs->lib.5plus.base-release.aar文件到原生工程工程的app->libs目录下

aar.png

4、打开项目app目录下的build.gradle文件,将aar包添加引用,加入如下代码:

implementation fileTree(dir: 'libs', include: ['*.aar'])


5、修改工程的targetSdkVersion大于等于21


targetSdkVersion.png

6、打开工程的Androidmanifest.xml文件,复制以下内容替换该文件中原有application节点下的内容

    <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节点下,避免merge冲突。

7、复制SDK->assets->data目录和目录下的文件到工程的src->main->assets目录下,新创建的工程默认没有assets目录,可在与java同级目录下创建assets目录。


assets.png

注: apps目录下应用资源的路径为[appid].www, appid为应用资源manifest.json文件中id节点的值,也就是mui项目manifest.json里的appid,如下图:


mui_manifest.png

8、将HBuilder里的代码进行本地打包,将应用资源打包进入Android项目的assets->apps对应目录下,HBuilder点击发行->本地打包->生成本地打包App资源,将路径选择到apps即可。


dabao.png

9、修改assets->data->dcloud_control.xml文件的apps->app->appid属性的值改为当前应用manifest.json文件id节点的值


control.png

运行项目,App便可进入到mui的页面,但是你会发现第一个页面是这样的


welcome.png

这是因为io.dcloud.PandoraEntry入口会先加载一个Splash页面,暂时不知道如何去掉,我们需要将应用的图标(文件名为icon.png)和启动图片(文件名为splash.png)放入drawable中,这样Splash页面就显示你的splash图片,如图


icon_splash.png
splash.png

二、插件开发

mui文档传送门

官方文档一开始可能看的有点蛋疼,这里就写个通俗点的例子,利用插件开发来进行动态权限申请,也就是在mui利用插件到原生里进行动态申请权限,然后将结果回调到mui这边js里。

1、JS扩展插件编写

实现同步扩展方法时,调用JS Plugin Bridge的window.plus.bridge.execSync()
方法,该方法可同步获取Native插件返回的运行结果。

void plus.bridge.execSync( String service, String action, Array<String> args ); 

实现异步扩展方法时,调用JS Plugin Bridge的plus.bridge.exec()方法,该方法会通知Native层插件执行指定方法,运行结果会通过回调的方式通知JS层。

void plus.bridge.exec( String service, String action, Array<String> args );  
test.js.png
2、实现扩展插件类
(1) 创建一个继承自StandardFeature的类

创建一个继承自StandardFeature的类,实现第三方插件扩展。
创建插件类需要引入的包

import io.dcloud.DHInterface.IWebview;
import io.dcloud.DHInterface.StandardFeature;
import io.dcloud.util.JSUtil;


(2) 实现扩展方法

Native层扩展插件的方法名需要和JS Plugin Bridge里windows.plus.bridge.exec()或windows.plus.bridge.execSync()方法的第二个传入参数相同,否则无法调用到指定的方法。

public void PluginTestFunction(IWebview pWebview, JSONArray array) 


(3) 返回值到js层

同步执行方法:
同步执行方法在返回结果时可以直接将结果以return的形式返回给js层,返回的结果需要调用如下方法处理要返回的字符串。

JSUtil.wrapJsVar("Html5 Plus Plugin Hello1!",true);  

异步执行方法:

JSUtil.execCallback(pWebview, cbId, (which==AlertDialog.BUTTON_POSITIVE)?"ok":"cancel", JSUtil.OK, false, false);   


3、关联JS插件名和原生类

在Android原生工程的assets\data\dcloud_properties.xml文件中声明插件类别名和Native层扩展插件类的对应关系

<properties>
    <features>
        ...
        <feature name="plugintest" value="com.kmvc.H5PlusPlugin.PGPlugintest"/>
    </features>

    <services>
        ...
        <service name="plugintest" value="com.kmvc.H5PlusPlugin.PGPlugintest"></service>
    </services>
</properties>

注:上面的value值便是扩展插件类的路径。

在应用的manifest.json文件中还需要添加扩展插件的应用使用权限,permissions节点下添加如下:


manifest_permission.png



4、使用实例

上面便是插件开发的核心步骤,下面举个例子,就是上面说的动态权限申请
(1)、html调用上面写好的js扩展插件,js扩展插件将调用原生那边的插件类相应方法

plus.plugintest.PluginTestFunction("PermissionCheck", "Plus", "AsyncFunction", "MultiArgument!", function(
                        result) {
    if(result[0] == "MyPermissionOK") {
        //getVersion();
    } else if(result[0] == "MyPermissionDenied") {
        mui.alert("关键权限必须打开,请进入设置打开相关权限,否则将影响应用正常使用!", "提示", function() {
        //getVersion();
        })
    } else {
        mui.alert("关键权限必须打开,请进入设置打开相关权限,否则将影响应用正常使用!", "提示", function() {
        //getVersion();
        })
    }
}, function(result) {
    mui.alert("权限申请失败,请进入设置打开相关权限,否则将影响应用正常使用!", "提示", function() {
    //getVersion();
    })
});

(2)、原生插件类被调用之后获取js传过来的值,并跳转到权限申请的原生页面

    public void PluginTestFunction(IWebview pWebview, JSONArray array) {
        // 原生代码中获取JS层传递的参数,
        // 参数的获取顺序与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)、权限申请的原生页面获取完权限申请结果后调用异步或同步方法回调到js层,这里用的异步,如下

 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方法,就是用来回调到js层的,具体参数如下

iWebView:扩展插件方法运行的窗口
callBackID:回调函数的唯一标识
pMessage:回调函数的参数
pStatus:操作是否成功,成功则使用JSUtil.OK,否则使用错误代码
isJson:回调函数参数是否为JSON数据

回调到js层后便可根据返回的结果进行处理,如上面第(1)步,我们根据权限申请的情况进行相应提示,并做了版本检查更新操作。

最终效果:


apply.png

ps:动态权限申请,需要targetSdkVersion大于等于23。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容