实现WKScriptMessageHandler,约定交互Handler
Apple要求新发布的app不能使用UIWebView。交互只总结WKWebView。
首先要约定 ScriptMessageHandler
的name,例如:lvJSCallNativeHandler
,具体细节不用说了,
主要回调逻辑实现在
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
先判断message.name,然后把message.body解析成NSDictionary
再用NSInvocation调用具体不同对接方法
用Safari浏览器的Develop功能可以调试app内置的H5页面。在console里输入
window.webkit.messageHandlers.lvJSCallNativeHandler
,可以打出原生添加的Handler对象。
H5d对接示例见nativeUtil-2.5.1.min.js
约定UserAgent
设置customUserAgent
来让H5可以区分运行环境,是否在App内,版本是多少,设备型号等。
在需要适配的时候有得用就行了。
标题和加载进度监测
- 由于WKWebview的
estimatedProgress
属性是支持KVO的,方便progressView显示加载进度。为了体验更好一点一般会有一个默认值,比如0.15,给用户一个加载快的假象。 title
属性也是支持KVO的,可以同步修改原生导航条的标题
约定App生命周期里的各个时机的通知方法
例如UIViewController的viewWillAppear:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.webView evaluateJavaScript:@"window.viewWillAppear && viewWillAppear();" completionHandler:nil];
}
原生事件 | 调js方法,通知H5 | 说明 |
---|---|---|
viewWillAppear | viewWillAppear() | 将要显示 |
viewWillDisappear | viewWillDisappear() | 将要消失 |
UIApplicationWillEnterForegroundNotification | willEnterForeground() | App将要到前台 |
原生返回按钮 | lvNativeBackCheck() | 点击原生返回按钮时询问H5要不要拦截处理 |
原生登录成功 | loginOnsuccess() | 给H5处理登录成功的机会,比如跳转页面 |
原生登录失败 | loginOnfail() | 给H5处理登录失败的机会,比如刷新页面,提示需要登录 |
登录状态打通
原生的登录状态应该在H5里能获得才行。
比如约定H5通过Cookie里的lvsessionid来判断登录状态,那就把lvsessionid
写入Cookie
,
注意域名的写法
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:
@{NSHTTPCookieDomain: @".example.com",
NSHTTPCookiePath: @"/",
NSHTTPCookieName: @"lvsessionid",
NSHTTPCookieValue: lvsessionid}];
WKHTTPCookieStore *cookieStore = self.webView.configuration.websiteDataStore.httpCookieStore;
[cookieStore setCookie:cookie completionHandler:nil];
常用约定方法,参数都是字典,返回值也都是字典
方法说明 | 方法名 | 说明 |
---|---|---|
显示Loading | lvJSShowLoading | |
隐藏Loading | lvJSHideLoading | |
获取位置 | lvJSGetLocation | |
打开相机扫描二维码 | lvJSOpenQRCodeScan | |
打开通讯录 | lvJSOpenContacts | 没有权限返回错误 |
读取NSUserDefault存储信息 | lvJSGetUserDefaultWithKey | |
设置NSUserDefault本地存储信息 | lvJSSetUserDefaultWithKey | |
页面跳转 | lvJSGoClass | 根据参数className类反射来判断跳哪个页面 |
浏览历史 | lvJSSaveHistory | |
获取屏幕尺寸和状态栏高度 | lvJSGetScreenSize | |
跳转到iOS系统APP设置页 | lvJSGoAppSettingPage | |
隐藏导航条 | lvJSHideNativeNavigationBar | |
显示导航条 | lvJSShowNativeNavigationBar | |
设置webView是否可以回弹 | lvJSSetWebViewBounces | |
复制文本到剪切板 | lvJSCopyToPasteboard | |
是否开启了精确定位 | lvJSGetAccuracyAuthorization | |
获取通知开关的状态 | lvJSGetNotificationType | |
navigationController里的堆栈Index | lvIndexOfNav | 当WebView在第一个的时候 不应该显示左上角的返回按钮 |
其他特殊约定
- App拦截特定规则的URL到原生页面的例外约定。
比如:门票详情的URL,piao后是产品id。
https://m.example.com/ticket/piao-983253
但是一些id是不能拦截的。这就需要约定例外规则,参数requireh5=1
https://m.example.com/ticket/piao-983253?requireh5=1
App在拦截时判断包含requireh5=1,就不会拦截。直接用WebView打开
- WebView是否多开(点击链接时在新的Controller里打开,而不是在当前controller里刷新)
WebView多开让HybirdApp变得更像原生的。约定参数
newtab=1
注意原生实现多开时要用copy和传递request(不要传递url,会丢失部分请求信息)同时也可以约定多开的展示方式,push还是present等