由于安卓和ios的处理方式不一样,所以我们要分开处理先贴上判断访问终端的代码

//判断访问终端

function browserVersion(){

var u = navigator.userAgent;

return {

trident: u.indexOf(‘Trident’) > -1, //IE内核

presto: u.indexOf(‘Presto’) > -1, //opera内核

webKit: u.indexOf(‘AppleWebKit’) > -1, //苹果、谷歌内核

gecko: u.indexOf(‘Gecko’) > -1 && u.indexOf(‘KHTML’) == -1,//火狐内核

mobile: !!u.match(/AppleWebKit.Mobile./), //是否为移动终端

ios: !!u.match(/(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端

android: u.indexOf(‘Android’) > -1 || u.indexOf(‘Adr’) > -1, //android终端

iPhone: u.indexOf(‘iPhone’) > -1 , //是否为iPhone或者QQHD浏览器

iPad: u.indexOf(‘iPad’) > -1, //是否iPad

webApp: u.indexOf(‘Safari’) == -1, //是否web应该程序,没有头部与底部

weixin: u.indexOf(‘MicroMessenger’) > -1, //是否微信 (2015-01-22新增)

qq: u.match(/\sQQ/i) == " qq" //是否QQ

};

通信原理之先了解webview


IOS容器在IOS客户端中,我们首先要提到的是一个叫UIWebView的容器,苹果对他的介绍是:

UIWebView是一个可加载网页的对象,它有浏览记录功能,且对加载的网页内容是可编程的。说白了UIWebView有类似浏览器的功能,我们使用可以它来打开页面,并做一些定制化的功能,如可以让js调某个方法可以取到手机的GPS信息。

但需要注意的是,Safari浏览器使用的浏览器控件和UIwebView组件并不是同一个,两者在性能上有很大的差距。幸运的是,苹果发布iOS8的时候,新增了一个WKWebView组件容器,如果你的APP只考虑支持iOS8及以上版本,那么你就可以使用这个新的浏览器控件了。

WKWebView重构了原有UIWebView的14个类,3个协议,性能提升的同时,赋予了开发者更加细致的配置(这些配置仅针对客户端IOS开发,对于前端H5来说,保持两种容器调用方法的一致性很重要)。

Android容器在安卓客户端中,webView容器与手机自带的浏览器内核一致,多为android-chrome。不存在兼容性和性能问题。

RN容器在react-native开发中,从rn 0.37版本开始官方引入了组件,在安卓中调用原生浏览器,在IOS中默认调用的是UIWebView容器。从IOS12开始,苹果正式弃用UIWebView,统一采用WKWebView。

RN从0.57起,可指定使用WKWebView作为WebView的实现

// rn js code

<WebView useWebKit={true} source={{ url: ‘https://m.douyu.com’ }} />

WebView组件不要嵌套在或原生点击组件中,会造成H5内页面滚动失效

h5向ios客户端发送消息;


在ios中,并没有现成的api让js去调用native的方法,但是UIWebView与WKWebView能够拦截h5内发起的所有网络请求。所以我们的思路就是通过在h5内发起约定好的特定协议的网络请求,如'jsbridge://bridge2.native?params=' + encodeURIComponent(obj)然后带上你要传递给ios的参数;然后在客户端内拦截到指定协议头的请求之后就阻止该请求并解析url上的参数,执行相应逻辑

在H5中发起这种特定协议的请求方式分两种:

  1. 通过localtion.href;

通过location.href有个问题,就是如果我们连续多次修改window.location.href的值,在Native层只能接收到最后一次请求,前面的请求都会被忽略掉。

  1. 通过iframe方式;

使用iframe方式,以唤起Native;以唤起分享组件为例

// h5 js code 将它封装一下

function createIframe(url){

var url = ‘jsbridge://getShare?title=分享标题&desc=分享描述&link=http%3A%2F%2Fwww.douyu.com&cbName=jsCallClientBack’;

var iframe = document.createElement(‘iframe’);

iframe.style.width = ‘1px’;

iframe.style.height = ‘1px’;

iframe.style.display = ‘none’;

iframe.src = https://segmentfault.com/a/url;

document.body.appendChild(iframe);

setTimeout(function() {

iframe.remove();

}, 100);

}

然后客户端通过拦截这个请求,并且解析出相应的方法和参数:这里以ios为例:

// IOS swift code

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {

let url = request.URL

let scheme = url?.scheme

let method = url?.host

let query = url?.query

if url != nil && scheme == “jsbridge” {

switch method! {

case “getShare”:

self.getShare()

default:

print(“default”)

}

return false

} else {

return true

}

}

看不懂就略过,非重点。。。。。

这里我们在请求参数中加上了cbName=jsCallClientBack,这个jsCallClientBack为JS调用客户端所定义的回调函数,在业务层jsBridge封装中,我们传入一个匿名函数作为回调,底层将这个函数绑定在window的jsbridge对象下并为其定义一个独一无二的key,这个key就是jsCallClientBack,客户端在处理完逻辑后,会通过上面已经介绍过的方法来回调window下的方法。

ps: 在将回调绑定在window下时,特别注意要使用bind保持函数内this的原有指向不变

IOS客户端调用H5方法


Native调用Javascript语言,是通过UIWebView组件的stringByEvaluatingJavaScriptFromString方法来实现的,该方法返回js脚本的执行结果。

// IOS swift code

webview.stringByEvaluatingJavaScriptFromString(“window.methodName()”)

从上面代码可以看出它其实就是执行了一个字符串化的js代码,调用了window下的一个对象,如果我们要让native来调用我们js写的方法,那这个方法就要在window下能访问到。但从全局考虑,我们只要暴露一个对象如JSBridge给native调用就好了。

调用客户端原生方法的回调函数也将绑在window下供客户端成功反调用,实际上一次调用客户端方法最后产生的结果是双向互相调用。

H5调用Android客户端方法


在安卓webView中有三种调用native的方式:

通过schema方式,客户端使用shouldOverrideUrlLoading方法对url请求协议进行解析。这种js的调用方式与ios的一样,使用iframe来调用native方法。通过在webview页面里直接注入原生js代码方式,使用addJavascriptInterface方法来实现。

// android JAVA code

class JSInterface {

@JavascriptInterface

public String getShare() {

//…

return “share”;

}

}

webView.addJavascriptInterface(new JSInterface(), “AndroidNativeApi”);

上面的代码就是在页面的window对象里注入了AndroidNativeApi对象。在js里可以直接调用原生方法。

使用prompt,console.log,alert方式,这三个方法对js里是属性原生的,在android webview这一层是可以重写这三个方法的。一般我们使用prompt,因为这个在js里使用的不多,用来和native通讯副作用比较少。

// android JAVA code

class WebChromeClient extends WebChromeClient {

@Override

public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {

// 重写window下的prompt,通过result返回结果

}

@Override

public boolean onConsoleMessage(ConsoleMessage consoleMessage) {

}

@Override

public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

}

}

一般而言安卓客户端选用1、2方案中的一种进行通信,从前端层面来讲,推荐客户端都使用schema协议的方式,便于前端jsBridge底层代码的维护与迭代。

Android客户端调用H5方法


在安卓APP中,客户端通过webviewloadUrl进行调用:

// android JAVA code
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

给大家分享一份移动架构大纲,包含了移动架构师需要掌握的所有的技术体系,大家可以对比一下自己不足或者欠缺的地方有方向的去学习提升;

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

给大家分享一份移动架构大纲,包含了移动架构师需要掌握的所有的技术体系,大家可以对比一下自己不足或者欠缺的地方有方向的去学习提升;

[外链图片转存中…(img-htG2WNZr-1711859610312)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐