前言
昨天遇到一个非常有趣的需求场景,背景如下:我们是一家电商平台,经常会做一些商品的促销专题活动。昨天我司产品经理找到我和APP的开发工程师,希望我们解决一个问题:在APP端点击专题活动中的商品,打开的页面是H5页面,而不是客户端的原生页面。产品经理希望打开原生页面,以让用户获得更好的体验。见下图,左图是在APP中打H5页面,右图是在APP中打开APP原生页面。
原因
发现了问题以后,我初步了解了导致这个问题的原因。原来,APP端展示的专题活动页面和小程序一样,采用的是webview的解决方案,即APP指定一个对象(我觉得是路径,不过据我司APP开发工程师介绍,APP中只有对象的说法,没有路径的说法),接收H5页面的链接,并将链接中的HTML铺到APP的对象(路径)中。用户点击专题中的商品链接也是同样的方式,因此最后展示出来的商品详情页就是H5页面,而不是客户端的原生页面。
小程序、安卓、苹果各不相同
小程序的处理逻辑
我目前在公司主要是负责小程序端的。在此之前,我接触过小程序类似的业务场景。在小程序中如果想要实现类似的逻辑,需要在H5页面的头部引入一段JS代码。这段JS代码的主要作用,是在window对象中加入一个新的名为wx的属性。这个属性是一个对象,有自己的属性和方法。通过调用wx.miniProgram.getEnv()方法,并传入一个回调函数,即
wx.miniProgram.getEnv(res => { if(res.miniProgram) { //小程序环境 let url; wx.miniProgram.navigateTo({url: url}); } else { //微信中打开内置浏览器 }})复制代码
以上判断完成之后,就完成了在小程序端跳转到原生页面的逻辑。
安卓客户端的处理逻辑
因为有这个基础,我下意识认为APP端如果想要实现类似的逻辑,也需要先引入一段类似的JS代码。但和APP工程师沟通后发现,客户端的API已经支持了这段JS代码需要实现的功能。我司APP工程师还给我展示了一段之前使用的代码:
if(window.android) { //判断android对象是否存在 window.android.navigateTo(url); //调用android分享} else { //调用ios支付方法! window.webkit.messageHandlers.navigateTo.postMessage(url);}复制代码
我的猜想是这样的:客户端(Android、iOS)中APP工程师通过API提供的方法,给JS的执行环境window增加了对应的属性:Android客户端增加的属性是android,iOS客户端增加的属性是webkit。这两个属性都是对象,在给这两个属性增加对应的方法以后,就可以直接在JS代码中引用了。为了证明我的猜想,我特意百度了一下“通过js调用android原生方法”,发现了以下这段代码。
//设置webviewmyWebView = (WebView) findViewById(R.id.myWebView);myWebView.getSettings().setJavaScriptEnabled(true);myWebView.addJavascriptInterface(new JavaScriptinterface(this),"android");myWebView.setWebViewClient(new myWebViewClient());//创建JavaScriptinterface类public class JavaScriptinterface { Context context; public JavaScriptinterface(Context c) { context= c; } /** * 与js交互时用到的方法,在js里直接调用的 */ @JavascriptInterface public void showToast(String ssss) { Toast.makeText(mContext, ssss, Toast.LENGTH_LONG).show(); }}//在JS中调用android原生方法复制代码
虽然没有学过客户端的相关知识,但这个逻辑还是一目了然的。从这段代码也可以看出,安卓客户端除了可以指定方法的名称外,还可以指定设置在window对象下的属性的名称,也就是上一行代码中的window.android。你可以改成window.Android、window.app,由app工程师指定。
确认该属性的名称后,再为这个属性添加方法,这个方法由H5页面的前端工程师和app开发工程师约定名字。app开发工程师实现逻辑跳转,前端工程师直接引用,即可实现跳转到app的原生页面。
苹果客户端的解决逻辑
与安卓客户端的实现逻辑一样,苹果客户端也是在window对象下添加指定的属性,在该属性下面添加方法,即可跳转到指定的app原生页面。不过需要注意的是,由于客户端API版本的不同,可能引用的方式也不同。目前我已经接触到了以下两个引用方式:
//第一种引用方式window.webkit.messageHandlers.shareLink.postMessage(shareData);//第二种引用方式window.RequiredSkill.shareLink(shareData)复制代码
总结
由于之前主要工作在小程序端,所以初次接触该问题时,习惯性的用了小程序的处理思路。也是第一次接触到和客户端的JS交互方式,感觉比较有意思,所以记录下来。
另外一个收获是,以前一直以为window对象就是指浏览器中的window;但通过解决这个问题发现,小程序、APP端也有相应的window对象,而且小程序和APP端的window对象还有独有的属性。想想确实是这个道理,不同的浏览器window对象的属性都不同,更何况不同的客户端?