背景
前段时间要做一系列的测试工具,需要在多平台:iOS、android、H5、公众号、小程序都实现。功能基本一样,就是在支付步骤需要区分平台,用对应的支付方式支付。本文讨论如何用一套小程序代码实现上述5个平台的开发。
效果图(左边为小程序,右边为浏览器):
omi-mp的介绍
omi-mp是腾讯前端框架omi的一个工具集,其目的是在于将小程序代码转成H5/Web,具体可以参见omi-mp的介绍Github。
omi-mp的转换并不是完全兼容小程序所有特性的,只支持了一小部分小程序API,并且存在了一些兼容特性,因此就需要开发者在开发小程序代码时,更多的以开发H5/Web的思路开发。
思路图和实现步骤
先实现小程序代码
1.初始化omi-mp目录工程:
npm i omi-cli -g
omi init-mp {工程名称}
cd {工程名称}
npm install
2.把小程序项目拷贝到src-mp
目录。
3.建议边实现小程序的过程中,不断的检验生成的H5的正确性,避免在最后阶段检验,否则如果出现问题,将不好定位,本地运行H5命令:
npm start //开发
再将小程序打包成H5/Web
打包H5/Web命令:
npm run build //发布
- 发布需要确认域名,修改
package.json
文件,修改"build": "PUBLIC_URL={发布域名} node scripts/build.js"
- 如果存在部分js文件丢失,可以尝试执行
gulp copyThen
公众号直接加载H5
公众号本质上也属于H5。
iOS/android App通过内嵌网页加载H5
iOS通过MKWebView加载H5。
android通过WebView加载H5。
- H5和原生App的交互部分可以通过JSBridge或者URL拦截实现
小程序代码如何区分平台
综上所述,除去部分iOS/android的原生代码外,基本所有的逻辑都是放在小程序里,按不同平台实现不同逻辑,小程序可以通过UserAgent以及Dom区分:
- 如果Dom树不存在
window
或者document
,为小程序平台; - iOS/android App内嵌网页可以自定义特殊的UserAgent,小程序代码可以通过此来区分iOS/android App平台;
- 微信App内嵌浏览器的UserAgent会带入
MicroMessenger/
关键字,可以按此区分公众号平台; - 其余为H5/Web平台;
if (typeof window == 'undefined') {
// 小程序
} else {
if (navigator.userAgent.userAgent.indexOf('ios-app') != -1
|| navigator.userAgent.userAgent.indexOf('android-app') != -1) {
// iOS/android
} else if (this.globalData.userAgent.indexOf('MicroMessenger/') != -1) {
// 公众号
} else {
// Web
}
}
iOS/android原生代码如何桥接
1.iOS/android需要先设置特殊UserAgent让小程序代码知道是iOS/android平台
iOS:
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"ios-app", @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
android:
webView.getSettings().setUserAgentString("android-app");
2.以URL拦截为例,小程序代码在当处于iOS/android平台的情况下,可以发送特殊URL,让iOS/android原生代码处理:
小程序:
if (navigator.userAgent.userAgent.indexOf('ios-app') != -1
|| navigator.userAgent.userAgent.indexOf('android-app') != -1) {
let url = 'app://pay?' + query;
window.location.href = url;
}
3.iOS/android拦截URL特殊处理
iOS:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSURL * url = navigationAction.request.URL;
if ([url.absoluteString hasPrefix:@"app://pay"]) {
// do something...
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
android:
webView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("app://pay")) {
// do something...
return true;
}
return false;
}
});
omi-mp的部分缺陷和一些踩过的坑
1.目前omi-mp只支持部分小程序部分API:
- wx.request
- wx.navigateTo
- wx.navigateBack
- wx.getSystemInfo
- wx.getSystemInfoSync
- wx.setNavigationBarTitle
- this.setData
- this.triggerEvent
如果用了其他的API,那么将会在输出H5报错。
2.支持组件,但是不支持组件的函数直接调用,替代方案可以用mitt,在page和component之间用mitt消息传递。
3.如果需要同时输出H5和Web,那么需要同时绑定click
和tap
事件(小程序只能绑定tap,Web只能绑定click,H5两者都可以),但是同时绑定又将会造成在H5的情况下,click
和tap
都会回调,导致两次调用。解决办法是可以在click
和tap
的地方同时加上判断,避免两次调用:
handleTap(e) {
if (!((typeof window == 'undefined') && e.type === "tap")) {
return;
} else if (!((typeof window != 'undefined') && e.type === "click")) {
return;
}
// do something...
}
4.wxml不支持Object字段的遍历处理。
5.如果编译不过,那么确认下是不是wxml中存在了一些特殊关键字,与omi的重了,导致失败。
6.即便在H5的场景下也无法使用document.getElementById()
。但是有替代方案,只是比较麻烦。
7.还有其它缺陷,有些忘了,待补充。
结语
omi-mp是一个不错的工具,在小程序不断变大变强的今天,能做到一套小程序代码,多端运行,降低开发成本。这里尤其感谢dntzhang的大力支持,希望omi越做越好。
一套代码,运行多端。目前唯一成熟的方案是uni-app,支持App、多家小程序和H5。
其他方案的坑都太多了。
[https://uniapp.dcloud.io/]
可以去看看,案例和开发者数量都是最多的。
数量最多,以至于质量嘛....DCloud商业宣传能消停点吗
产品都是免费的,不存在商业。质量肯定是当前最成熟的
跨平台开发,听起来很爽,只用一套代码。
真要遇到坑了,让你欲哭无泪。
小程序本身就该直接用h5,自己搞出的东西真的害死人
早该利用成熟的 Web 生态了,小程序也是 WebView,搞了个 Demo 级别的开发工具,可把大家害苦了。
首先,说小程序开发者工具是 Demo 级是很不负责任的,而且代码开发你完全可以不用小程序开发者具的编辑功能,小程序开发者工具的主要作用是本地进行小程序/公众号开发调试 ~
其次,并不是没有利用成熟的 Web 生态,而且正好相反,微信小程序正是利用了成熟的 Web 生态,只是在安全层面的考虑,对 Web 环境做了较大的限制,同时相对于传统 Web 又集成了微信的能力。
最后,小程序在开发体验上有较大的缺陷,所以推荐使用 一款小而美的小程序脚手架,让你更流畅的开发小程序
你这个最后,其实就是证明我的观点,真是把大家坑苦了 。
所以,在开发的过程中我开发了一套小程序的脚手架,补全了开发体验上的短板 ~~ 欢迎使用,欢迎 Start ~~
第 39 Start,望早日成熟,扬名四海。
已经在生产环境中运行了近一年,比较稳定,可以放心使用
前来支持!
Omi-mp的确可以解决很大程度上的多端或者小程序框架的不足
当然适合自己做项目,如果是群发小程序或者移植小程序的还是适合更加成熟的多端框架
typeof window 并不可靠,建议改用 typeof wx == "object" && wx.version
你是在开发工具的控制台输出的,有 window 很正常,因为开发工具就是浏览器来的。
实际在小程序代码里面输出的话,就是 undefined
总得在开发工具调试吧?
你这是在控制台调试,小程序的代码在开发工具运行的时候,里面 window 就是 undefined。
控制台的环境不等于小程序的环境
我个人习惯在控制台写测试代码,妥妥了,直接 IDE 里写,一气呵成,爽。
大佬牛逼啊!!
看到文章,马上把项目拉进来试了一下,结果。。。。。报错
iOS通过MKWebView加载H5。 这个是WKWebView吧
wepy 也好,这个也好,居然是腾讯的。明明小程序也是腾讯,为什么不直接在小程序的框架上改?
不同的业务部门咯。