北斗星辰 發表於 2020-7-31 16:41:00

Android uni-app封装原生插件

<h1 style="text-align: center"><strong>Android uni-app封装原生插件</strong></h1>
<p>&nbsp;</p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731161440574-1563594351.png"></strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2><strong>uni-app是什么?</strong></h2>
<p>一个使用Vue.js开发所有前端应用框架,开发者编写一套代码,可发布到ios、Android、H5、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉)等多个平台。</p>
<p>如果你还没有了解uni-app是什么:点击这里:这篇文章举例说明。。。</p>
<p>&nbsp;</p>
<h2>uni-app的特点</h2>
<ul>
<li>跨平台更多
<ul>
<li>真正做到“一套代码、多端发行”!</li>
<li>条件编译:优雅的在一个项目里调用不同平台的特色功能!</li>
</ul>
</li>
<li>运行体验好
<ul>
<li>组件、api与微信小程序一致</li>
<li>兼容weex原生渲染</li>
</ul>
</li>
<li>通过技术栈,学习成本低
<ul>
<li>vue的语法、微信小程序的api</li>
<li>内嵌mpvue</li>
</ul>
</li>
<li>开放生态,组件更丰富
<ul>
<li>支持通过npm安装第三方包</li>
<li>支持微信小程序自定义组件及SDK</li>
<li>兼容mpvue组件及项目</li>
<li>App端支持和原生混合编码</li>
<li>DCloud将发布插件市场</li>
</ul>
</li>
</ul>
<p>&nbsp;</p>
<h2><strong>uni-app封装原生插件</strong></h2>
<h3>1.Android离线SDK下载:</h3>
<p>点击下载,两个SDK均可。</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731163211592-456452723.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>下载完成,解压备用:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731163317086-844758698.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>2.新建Android项目</h3>
<p>打开Android Studio,建立一个No Activity项目。在菜单栏选择<strong>File&gt;New&gt;New Project</strong></p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731164046873-1165869364.png"></strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>然后Next:填写项目名,包名,已经API Level。</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731164231726-1642253506.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;然后Finish,为了更好的使用,我们把它转到Project视图。接下来创建开发的模块(Module)</p>
<p>点击<strong>File&gt;New&gt;New Module.</strong></p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731164534286-1851601392.png"></strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>然后选择Android Library,点击Next:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731164616588-376895213.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;自定义Library名 和包名,点击Finish</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731164656571-280340384.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>创建完毕视图如下:</p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731164748162-1462615953.png"></strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>接下来打开testplugin项目里的build.gradle,将原生的dependencies下默认生成的依赖注释掉,添加uni-app所需库的依赖:</p>
<div class="cnblogs_code">
<pre> compileOnly <span style="color: rgba(128, 128, 128, 1)">"</span><span style="color: rgba(128, 128, 128, 1)">com.android.support:recyclerview-v7:25.3.1"</span>
compileOnly <span style="color: rgba(128, 128, 128, 1)">"</span><span style="color: rgba(128, 128, 128, 1)">com.android.support:support-v4:25.3.1"</span>
compileOnly <span style="color: rgba(128, 128, 128, 1)">"</span><span style="color: rgba(128, 128, 128, 1)">com.android.support:appcompat-v7:25.3.1"</span>
implementation <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 128, 0, 1)">com.alibaba:fastjson:1.1.46.android</span><span style="color: rgba(128, 0, 0, 1)">'</span>   //一会会用到fastjson</pre>
</div>
<p>添加完成如下图所示:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731165733505-109461150.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>另外把导入的<strong>uniapp-release.aar</strong>插件,它是扩展module主要依赖库</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731170107787-904223382.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;回到刚刚创建的testplugin的build.gradle中,接下来进行导入aar需要的配置操作:</p>
<p>添加: 放在android{}外</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">repositories {
    flatDir {
      dirs </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 128, 0, 1)">libs</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
    }
}</span></pre>
</div>
<p>然后在dependencies内添加:</p>
<div class="cnblogs_code">
<pre>compileOnly fileTree(dir: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 128, 0, 1)">../app/libs</span><span style="color: rgba(128, 0, 0, 1)">'</span>, include: [<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 128, 0, 1)">uniapp-release.aar</span><span style="color: rgba(128, 0, 0, 1)">'</span>])</pre>
</div>
<p>添加完毕,如下图:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731170539456-1631989946.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>然后<strong>同步Sync Now</strong>!</p>
<p><strong>官网文档提醒:</strong></p>
<p>工程gradle配置的为gradle-4.6-all版本,使用的是新版本的依赖方式。如果您使用的是老版本的gradle,可点击链接进行修改依赖方式。</p>
<p>&nbsp;</p>
<h3>3.原生插件的开发</h3>
<p>以扩展Module为例,如图创建类TestModule:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731171052285-925706195.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Module扩展注意事项:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731171155203-2124840493.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;写一个小demo:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.util.Log;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.alibaba.fastjson.JSONObject;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.taobao.weex.annotation.JSMethod;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.taobao.weex.bridge.JSCallback;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.taobao.weex.common.WXModule;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> TestModule <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> WXModule{
    String NAME</span>="name"<span style="color: rgba(0, 0, 0, 1)">;
    String AGE </span>="age"<span style="color: rgba(0, 0, 0, 1)">;

    @JSMethod(uiThread </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> testText(JSONObject options, JSCallback callBack){
      Log.e(</span>"TestModule", "成功调用!"<span style="color: rgba(0, 0, 0, 1)"> );
      String name </span>=<span style="color: rgba(0, 0, 0, 1)">options.getString(NAME);
      String age </span>=<span style="color: rgba(0, 0, 0, 1)">options.getString(AGE);
      JSONObject data </span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> JSONObject();
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (name !=<span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; !name.isEmpty() &amp;&amp; age !=<span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; !<span style="color: rgba(0, 0, 0, 1)">age.isEmpty()){
            </span><span style="color: rgba(0, 0, 255, 1)">int</span> _age =<span style="color: rgba(0, 0, 0, 1)">Integer.parseInt(age);
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (_age&lt;0 || _age&gt;30<span style="color: rgba(0, 0, 0, 1)">){
                data.put(</span>"code","不合格!"<span style="color: rgba(0, 0, 0, 1)">);
            }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                age</span>=(_age&gt;0 &amp;&amp; _age&lt;10) ? "0"+<span style="color: rgba(0, 0, 0, 1)">age:age;
                data.put(</span>"code","合格:"+"姓名_"+name+",年龄_"+<span style="color: rgba(0, 0, 0, 1)">age);
            }
      }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
            data.put(</span>"code","输入无效!"<span style="color: rgba(0, 0, 0, 1)">);
      }
      callBack.invoke(data);
    }
}</span></pre>
</div>
<p>&nbsp;</p>
<h4>接下来在本地注册插件(一):</h4>
<p>在<strong>app&gt;src&gt;main</strong>目录下创建<strong>assets</strong>文件夹</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731171440282-899497458.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731171454598-1949839310.png"></p>
<p>&nbsp;</p>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731171458842-905179687.png"></p>
<p>&nbsp;</p>
<p>&nbsp;在<strong>app&gt;src&gt;main&gt;assets</strong>目录下创建<strong>dcloud_uniplugins.json</strong>文件,然后添加:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"nativePlugins"<span style="color: rgba(0, 0, 0, 1)">: [
    {
      </span>"plugins"<span style="color: rgba(0, 0, 0, 1)">: [
      {
          </span>"type": "module"<span style="color: rgba(0, 0, 0, 1)">,
          </span>"name": "Test-Module"<span style="color: rgba(0, 0, 0, 1)">,
          </span>"class": "com.test.testplugin.TestModule"<span style="color: rgba(0, 0, 0, 1)">
      }
      ]
    }
]
}</span></pre>
</div>
<p>&nbsp;</p>
<h4>注册方法(二):</h4>
<p>对创建的Module扩展testplugin进行操作,在 src&gt;main&gt;java&gt;插件包名(这里是com.test.testplugin)目录下创建类TestModule_AppProxy</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172448084-234529660.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172457035-2032775893.png"></strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>TestModule_AppProxy类要实现AppHookProxy接口,在onCreate()方法中添加weex注册相关参数或填写插件需要在启动时初始化的逻辑。</p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172518904-624835553.png"></strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div>
<div>在<strong>hooksClass</strong>节点填入你创建的实现AppHookProxy接口的实体类的完整名称 (注:有些需要初始化操作的需求可以在此处添加逻辑,无特殊操作仅使用第一种方式注册即可无需集成AppHookProxy接口)</div>
<img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172714363-808100703.png">
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>注册完毕,开始打包插件</p>
<p>在Gradle&gt;testplugin&gt;Tasks&gt;other目录下找到assembleRelease,双击等待系统编译出扩展module的aar文件</p>
<div>
<div>注意:官方文档中是<em><strong>选择</strong></em><em><strong>Gradle---&gt;插件module---&gt;Tasks---&gt;build---&gt;assembleRelease编译module的aar文件</strong></em>,在新版本的AndroidStudio中,<strong>assembleRelease</strong>和<strong>assembleDebug</strong>被转移到other目录下。</div>
</div>
<img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172832587-1298320577.png">
<p>&nbsp;</p>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172839064-397103712.png"></p>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172845159-5274535.png"></p>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172856158-1185241826.png"></p>
<p>&nbsp;</p>
<p>&nbsp;成功后在testplugin&gt;build&gt;outputs&gt;aar目录下就可以找到相关插件了</p>
<img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731172938670-1484437150.png">
<p>&nbsp;</p>
<h2>&nbsp;</h2>
<h2>4.HBuilderX导入和使用本地插件</h2>
</div>
<div>创建uni-app默认项目TestModule</div>
<div><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173258491-405056811.png">
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>
<p>参照官方文档中的目录规范,将刚才打包的插件放到nativeplugins&gt;插件文件夹名称(我的是Test-Module)&gt;android目录下,没有相关目录就一步步创建。</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173321203-904346556.png"></p>
<p>&nbsp;</p>
<p>&nbsp;创建package.json——uni原生插件描述文件,放到插件文件夹名称目录下,与android文件夹并列</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173335528-650935996.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>注意</strong>:插件标识id必须在对应android和ios节点下plugins中进行注册,与name字段值一致。name下的class是注册插件的类名,也要填对。</p>
<p>这里因为只有android插件,就把ios节点全部删掉,在这里直接注释的话是无效的。</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173435967-847896815.png"></p>
<p>&nbsp;</p>
<p>&nbsp;还有要注意的一点:插件标识id一定要与插件文件夹名称一致,不然在云打包时会提示<strong>插件不合法:该插件在nativePlugins目录下不存在。</strong></p>
<p>在manifest.json下配置App原生插件</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173522146-1571855914.png"></p>
<p>&nbsp;</p>
<p>&nbsp;勾选并确认</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173533582-158492787.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>parameters信息根据需求配置</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173544362-561133916.png"></p>
<p>&nbsp;</p>
<p>&nbsp;接下来在HBuilderX内对项目中的index.vue文件(在pages&gt;index目录下)做出一定更改,以便后续测试开发的原生插件。</p>
<div class="cnblogs_code">
<pre>&lt;template&gt;
    &lt;view class="container"&gt;<span style="color: rgba(0, 0, 0, 1)">
      姓名</span>&lt;input v-model="name" placeholder="点此编辑姓名" &gt;
      &lt;br&gt;<span style="color: rgba(0, 0, 0, 1)">
      年龄</span>&lt;input v-model="age" placeholder="点此编辑年龄" &gt;
      &lt;br&gt;
      &lt;button type="default" @click="test"&gt;提交&lt;/button&gt;
      &lt;view&gt;{{name}}&lt;/view&gt;
      &lt;view&gt;{{age}}&lt;/view&gt;
      &lt;view&gt;{{ result }}&lt;/view&gt;
    &lt;/view&gt;
&lt;/template&gt;

&lt;script&gt;
    <span style="color: rgba(0, 0, 255, 1)">var</span> testModule = uni.requireNativePlugin("Test-Module"<span style="color: rgba(0, 0, 0, 1)">);
    export </span><span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)"> {
      data() {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
                name:</span>""<span style="color: rgba(0, 0, 0, 1)">,
                age:</span>""<span style="color: rgba(0, 0, 0, 1)">,
                result:</span>"暂未提交"<span style="color: rgba(0, 0, 0, 1)">
            }
      },
      methods: {
            test(){
                testModule.testText({
                  </span>'name':<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name,
                  </span>'age':<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.age,
                },
                (ret) </span>=&gt;<span style="color: rgba(0, 0, 0, 1)">{
                  </span><span style="color: rgba(0, 0, 255, 1)">this</span>.result="[提交反馈]"+<span style="color: rgba(0, 0, 0, 1)">ret.code;
                })
            }
      }
    }
</span>&lt;/script&gt;</pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173722037-1110614591.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2>5.运行项目</h2>
<p>打包自定义基座:</p>
<p>运行(R)&gt;运行到手机或模拟器(N)&gt;制作自定义调试基座(P)</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731173925849-1691110993.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>配置App云端打包信息:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174124845-273374213.png"></p>
<p>&nbsp;</p>
<p>&nbsp;云端打包:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174142192-1401244350.png"></p>
<p>&nbsp;</p>
<p>&nbsp;提交到云端服务器:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174154285-2132651930.png"></p>
<p>&nbsp;</p>
<p>&nbsp;打包成功:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174333281-474493270.png"></p>
<p>&nbsp;</p>
<p>&nbsp;打包成功后需要在下图位置确保开启自定义调试基座功能:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174352167-1928564490.png"></p>
<p>&nbsp;</p>
<p>&nbsp;可以在项目unpackage下看到打包后的测试apk文件:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174404054-652942205.png"></p>
<p>&nbsp;</p>
<p>&nbsp;启动模拟器,或者真机运行:</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174423871-199924159.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>进入测试项目:</strong></p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174504556-49402519.png"></strong></p>
<p>&nbsp;</p>
<p>&nbsp;输入姓名tom和年龄9(大于0小于10前面自动补0)测试插件,点击提交</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174516807-1089212766.png"></p>
<p>&nbsp;</p>
<p>&nbsp;反馈提交结果</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174528175-2195180.png"></p>
<p>&nbsp;</p>
<p>&nbsp;把年龄改为31(插件设置年龄范围为0~30),反馈如下</p>
<p><img src="https://img2020.cnblogs.com/blog/1752318/202007/1752318-20200731174539319-258289094.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>至此,测试成功!</p>
<h2>&nbsp;<strong>参考</strong>:</h2>
<ul>
<li>官方文档原生插件开发!</li>
<li>
<p class="_1RuRku">uni原生插件Android开发流程一览—Module扩展</p>
</li>
</ul>
<h2>最后:请留下您的赞!阿里嘎多.</h2>
<h2>&nbsp;</h2>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/Mr-East/p/13410568.html
頁: [1]
查看完整版本: Android uni-app封装原生插件