如何通过小程序实现跨平台开发
发布于 5 年前 作者 scao 3796 次浏览 来自 分享

背景

前段时间要做一系列的测试工具,需要在多平台: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,那么需要同时绑定clicktap事件(小程序只能绑定tap,Web只能绑定click,H5两者都可以),但是同时绑定又将会造成在H5的情况下,clicktap都会回调,导致两次调用。解决办法是可以在clicktap的地方同时加上判断,避免两次调用:

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越做越好。

10 回复

一套代码,运行多端。目前唯一成熟的方案是uni-app,支持App、多家小程序和H5。

其他方案的坑都太多了。

[https://uniapp.dcloud.io/]

可以去看看,案例和开发者数量都是最多的。

看到文章,马上把项目拉进来试了一下,结果。。。。。报错

if (typeof window == ‘undefined’) {

// 小程序

}

typeof window 并不可靠,建议改用 typeof wx == “object” && wx.version

早该利用成熟的 Web 生态了,小程序也是 WebView,搞了个 Demo 级别的开发工具,可把大家害苦了。

小程序本身就该直接用h5,自己搞出的东西真的害死人

前来支持!

Omi-mp的确可以解决很大程度上的多端或者小程序框架的不足

当然适合自己做项目,如果是群发小程序或者移植小程序的还是适合更加成熟的多端框架

iOS通过MKWebView加载H5。  这个是WKWebView吧

跨平台开发,听起来很爽,只用一套代码。

真要遇到坑了,让你欲哭无泪。

这算是什么报错?

wepy 也好,这个也好,居然是腾讯的。明明小程序也是腾讯,为什么不直接在小程序的框架上改?

回到顶部