技术背景了解
Uniapp可以解决的问题
Uniapp是一个跨平台开发技术应用,意在使用js代码来开发多端平台,如Android、IOS、HarmonyOS这些移动端平台,当然最火的还是开发小程序应用。
旨在减轻前端开发人员的压力,让前端开发人员无需学习Android、IOS知识,仅通过一套JS代码就能开发出对应平台的APP,那么Uniapp真的有这么神奇吗?就让这篇文章来揭开Uniapp这个平台的面纱吧。 前置技能: 1. js技术 2. Android技术 3. IOS技术
开发工具 1. HBuildX(开发UI页面) 2. Android Studio(开发Android插件包) 3. Xcode(开发IOS插件包)
Uniapp简单实现原理
疑问:那么Uniapp是如何实现一套JS代码开发多端平台呢?
在回答这个问题的时候,我们可以思考一下其他的跨平台开发是如何实现跨平台呢?例如我在C中开发一套代码,怎样才能既可以在Linux系统上正常运行,又可以在Windows系统上来运行,实际上我们需要在每一个平台上通过专门的编译工具编译成各个平台上可以使用的代码就可以了,其中 Uniapp就是充当了这个"桥",把来自JS的消息发送给分发给各端去处理。而我们知道各端的WebView又是可以订阅JS消息,又是可以发送JS消息的,所以Uniapp就是利用了这个机制,通过各端WebView来实现与JS代码的交互。
大致流程就是如下
——————
疑问2: 那么Uniapp该如何去调用原生的功能呢?例如调用相机/麦克风这些原生功能
其实从上面的流程我们知道了UniappSDK就是充当了"桥",负责将两端的消息进行传递处理,那么我们可以在Native端中实现好了麦克风/相机功能,当收到来自JS中某个特定消息后,那么Native端去调用这个麦克风/相机功能就可以了。如果JS端要监听原生端的某个消息也是同理,监听JS中的某个特定事件,Native端负责去发送就可以了。
从上面我们知道了UI部分的JS代码可以用于webview来进行UI方面的渲染,展示UI效果,而特定的Native功能,则又交由各端去单独实现,这样就能做到了一套JS代码多端实现。
看起来很美好,但是实际上在开发中上面的方式还不能满足我们的开发,仅是通过WebView展示UI是不够的,在Android和IOS中WebView只是其中的一种View而已,而在日常开发中,需要用到很多其他我们自己封装的View如VideoView这些,那么这些View又该如何暴露给JS端控制呢?
面对这个问题,Uniapp的做法是把这些View封装成Module,通过“插件”的形式来导入这些module,这样就能在JS端导入这些Module来控制这些封装的View。而封装出来的这些”插件“包就是我们常说的离线插件包。既然有离线插件包,那么就有在线插件包,关于两者的差别我在后面详细说明。
插件包封装
我们可以在Uniapp的项目中的package.json中去对各个模块进行定义,提供给前端使用,那么在JS代码中就可以去引入这些module,去调用这些封装起来的插件
像在上面的这些图片中,就定义了多个模块,上面图片仅仅展示了Android的模块,不过IOS也是同理。
但是我们知道View的定义不仅是只有代码部分,还有静态资源这些,所以封装离线插件包,我们需要将这些静态资源和代码部分都需要封装在一起。
在Android中,我们都是可以将资源和代码一并封装成aar包,供Uniapp使用,但是由于是使用aar包的方式引入,那么不可避免就会有aar包依赖的问题,aar包不能像远程依赖的方式,能自动将包所依赖的依赖包一并打包出来,需要我们手动将aar包所依赖的各个jar包、aar包单独放进去Uniapp中去使用。
在IOS中,代码是通过Framework包封装,静态资源则是通过Bundle资源进行封装的,所以IOS的封装离线插件包就需要将Framework包Bundle资源找出来一并添加进Uniapp才行。
这些封装好的资源包需要放置在HBuildX中nativeplugins目录下
可以看到上面图片封装了MediaPlayer插件、ToolZip插件、VodUniPlugin插件这些插件,这些插件都是由Android、IOS端打包封装出来,供由JS端去调用驱动。
注意:插件包要摆在nativeplugins目录下
离线插件包与在线插件包区别
Uniapp客户在使用我们的SDK有两种方式,分别是云打包依赖和离线打包依赖,这两种方式取决于客户的技术能力。
在上面我们知道了Android项目是依赖aar包,IOS项目是依赖Framework包,有了aar包和Framework包后就能将打出对应的apk包和ipa包
(安卓上是运行apk,依赖于Android的打包工具进行打包封装成apk文件后才能在Android系统上安装运行,而这个打包工具是异常繁琐,一般都是使用Android-Studio这个IDE提供的打包方式进行一件打包,IOS则是同理使用XCode来打包成ipa包)
所以理论上客户需要的就是aar包和Framework包而已,但是大部分使用Uniapp的用户都可能仅有前端的技能,没有点亮IOS和Android开发的技能点,不会使用Android Studio和XCode,Uniapp为了兼顾这部分的用户群体,推出了云打包的操作,就是说你可以上传你的js代码上到他的服务器上,然后选择你要添加的aar/Framework包,这些aar/FrameWork包就是封装好并已经上传到Uniapp服务器的SDK包,然后交由Uniapp打包机打包出对应的apk包和ipa包出来,这样就能做到前端开发和原生开发的分离,让前端开发人员也能不用学习Android、IOS也能调用这些原生端的功能。而我们每次发板的其实上传这些SDK包到Uniapp的服务器上,供这些前端开发人员使用。
Uniapp开发者就可以到UniAPP服务上挑选他需要的功能一并打包到他的项目中,这样就能极大方便开发。
云打包看起来很美好但是每走一步都要经过Uniapp的服务器,服务器上的每一步操作都是要花费钱的,所以导致云打包是要排队的,要不就是充钱插队。
因此面对这种情况,有了离线插件包的操作,在上面Uniapp负责的工作就是 收集插件包,收集JS代码、打包出apk\ipa包,那么上面Uniapp做的操作全部交由用户自己来完成,这个步骤就是使用离线插件包。
这也意味着用户需要有Android开发、IOS相关开发知识才可以。构建了离线工程,就可以把aar包/Framework包、js代码放入工程中打出需要的apk和ipa包了。
而且使用离线工程会更加灵活,所以有不少客户都是能直接使用离线插件包的。
构建插件工程
构建插件工程可以参考官方的文章,这里不做过多的介绍了
那么该如何构建插件工程呢?当前我们的项目是已经搭建好了,如果需要重新构建一个新的项目,那么可以参考上面的文档,本质上就是集成UniappSDK到本地项目中,通过sdk来加载js代码和受HbuildX来控制。
之后我们的调试和打包离线插件包都是在这个离线插件工程上面操作了。其中最为用要的是插件项目的包名必须与HBuildX中的AppId对应上,否则就不能通过HBuildX来调试程序了。
插件工程中最为重要的是3份资源:JS资源、UniappSDK、需要集成的SDK资源
只要有上述的3份资源就能构建出需要的apk包和ipa包了。其中JS负责的是UI显示的逻辑,UniappSDK负责 js与native传递的“桥”,集成的SDK负责的就是复杂的原生功能。
开发过程
下面将讨论如何将在原生构建好的SDK工具提供给插件工程,重新封装成一个插件包给前端JS调用。
构建JS资源
通过上面我们了解到了,离线插件过程需要的是aar包/Framework包,JS资源包,UniappSDK,这里就讨论一下JS资源该如何构建。(JS资源负责的是UI界面的显示)
Uniapp的前端页面开发是使用HBuildX来进行开发的,在HBuildX中编写好JS代码后(每次编写完毕记得control+s保存代码)通过点击生成本地App资源来生成对应的前端资源。
这样就能生成出对应的本地JS资源(目录unpackge/resources/[APPID]/www) 然后把这个www文件拷贝到你的离线插件工程中,覆盖掉原来的www文件即可
Android位置:app/src/main/assets/apps/__UNI__1B5A603/www
IOS为主:/Pandora/apps/__UNI__4E1AA66/www
然后重新Build就好了(build可能js资源更新不生效,这个时候需要删除本地apk,重新安装一下)
离线工程依赖的UI显示是依赖于这个JS资源的,所以Uniapp是支持热更新UI的,也就是可以将新的UI资源打包成APP资源包,然后上传到Uniapp的服务器,然后apk/ipa包会尝试拉取最新的JS资源包,然后画面显示就使用最新的JS资源包,从而做到热更新效果,不需要用户重新去安装下载最新的apk/ipa包,但是这个仅限于JS资源,插件包就无法进行热更新了。
那么每一次改动JS代码难道都要执行上面的步骤才能看到改动效果吗?那不是要忙死了?其实不用担心,HBuildX中有提供热更新的方式,每次改动都能立刻看到效果,在后续就会介绍如何使用热更新。
构建AAR/Framework包
在原来项目SDK更新/改动后,我们也需要将更新后SDK放置进离线插件工程中,在Android中静态资源可以一并打包成aar包,所以我们只需要更新AAR包即可,而IOS则更新Framework包和Bundle静态资源。
IOS更新Framework包则是简单很多,只需要执行pod install 就可以对Framework包进行更新了(前提是新版本SDK包已经发布到了CocoaPods中),如果更新内容还涉及到了Bundle静态资源的话,那么就需要将新的Bundle资源拷贝过去就可以了。
之后我们将新的SDK导出为对应的aar/Framework包放入到插件项目下就好了。
上面就展示了在Android中这些aar包摆放在插件项目的路径,将用到的原生SDK放入到插件项目下就可以了。
构建离线插件包
当前我们的离线插件工程已经构建完毕了,也导入了需要用到的原生SDK包,那么现在我们需要导出前端可以调用的离线插件包。
在Android中执行Glide脚本,生成出uniapp插件module对应的release.aar包,在点播项目中生成出来的是uniplugin_release.aar包,因为是aar包的形式,aar包不能把所有的依赖包一并打包进去,所以我们还要手动将点播SDK需要依赖的aar包找出来,一并放入到HbuildX-nativeplugins目录下,不过当前已经归纳好了,可以根据这次需要更新的aar包一并更新到HBuildX项目下的nativeplugins目录下。
在IOS则需要build一下项目,获取到新产物uniplugin.framework包,并且将pop install更新的framework包一并更新到HBuildX项目下的nativeplugins目录下就好了。
调试Uniapp程序
调试Uniapp程序可以参考这篇文章 离线打包制作自定义基座
一般Uniapp程序的开发流程是,既要改动JS资源,又要改动插件包的内容,这两个过程甚至是交替操作的,并不是简单做JS资源改动,再去改动插件包内容,那么这个过程该如何做呢?
这个就涉及到了运行自定义插件包项目,这样就能动态改动js代码立刻就能响应更改,不需要频繁重复生成本地打包APP资源,重复安装/删除应用。
使用自定义插件包来调试项目的话,这里测试是使用HbuildX 3.5.3版本,使用新版本HBuildeX进行调试Android应用会提示
”同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示“
估计是新版本的SDK和当前的离线插件包使用的SDK版本不一致导致的,所以推荐使用HbuildX 3.5.3版本进行开发,而ios调试则是正常
1、打出debug包 将最新的JS资源包更新到离线插件工程中,然后生成对应的apk包/ipa包,将生成出的apk包改名为android_debug.apk , ipa包改名为iOS_debug.ipa包,然后放入到HbuildX项目中的unpackage/debug目录下即可
2、运行自定义插件包
当设置好最新的debug包后,可以点击运行-运行到手机或模拟器-运行到Android/IOS APP基坐,然后选择自定义标准基座即可,当你更改了HbuildX中的js代码后,按下"control-s"保存代码即可完成热更新调试,设备就会更新最新的画面。
发布流程
1、复制Demo工程、移除离线插件文件夹、unpackage文件夹。(没有改动可以不更新)
2、将Manifest.json中的appid移除,否则上传提交不通过。
3、将Demo压缩成zip:XXXUniPluginDemo.zip
4、将离线插件包压缩成zip:XXXUniPlugin.zip
5、更新CHANGELOG、README
然后将Demo工程和离线插件包一并发布到Uniapp服务器上就可以了。
Uniapp开发者就能在Uniapp服务器上选择你的SDK去使用了。
发布注意事项:
1、每日有免费的云打包打包额度,可以使用大概2次,且ios和android包是分开计算的,可以通过云打包测试新的插件工程是否没有问题,云打包是可以选择本地插件包(放入nativeplugins目录下的插件包)+云插件一并打包,如果要测试本地的插件包,可以在manifest.json-App原生插件配置中选择本地插件和选择要用的云端插件包
2、打包ipa包需要提供对应的profile文件和私钥证书,这个可以找IOS项目帮忙签出这两份文件,ios的安装不像Android,每台设备都需要对应证书才能安装,所以如果是这种测试用途包,需要在签名文件中把对应的设备id写入到证书才行