不积跬步,无以至千里;不积小流,无以成江海
在现在混合开发的时代,纯原生越来越不现实,基本上每个app都会和h5有交集,熟悉原生和h5之间的交互,快速实现需求也是每个coder需要的必备技能。(本文的webView
都是特指WKWebView
)
一、先记录一些h5和iOS的交互,不涉及rn和flutter。h5和原生是通过js构建
的桥梁
1、iOS通过js调用h5
- (void)evaluateJavaScript:(NSString *)javaScriptString
completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
webView提供了执行js的方法,我一般是在加载完html后执行一些js,比如获取页面高度
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
NSString *doc = @"document.body.outerHTML";
[webView evaluateJavaScript:doc
completionHandler:^(id _Nullable htmlStr, NSError * _Nullable error) {
if (error) {
NSLog(@"JSError:%@",error);
}
NSLog(@"html:%@",htmlStr);
}] ;
}
2、h5通过js回调原生
iOS:需要在初始化webView配置
configuration
,给configuration添加相应的userContentController
说明:这里没有直接使用WKScriptMessageHandler
而是自定义它的代理,直接使用是强引用,造成循环引用,这个页面就不能释放
下面以PayParam
为例:
@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>
@property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate;
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;
@end
@implementation WeakScriptMessageDelegate
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate
{
self = [super init];
if (self) {
_scriptDelegate = scriptDelegate;
}
return self;
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
[self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}
webView初始化
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
[userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"PayParam"];
cfg.userContentController = userContentController;
WKWebView *webView = [[WKWebView alloc] initWithFrame:(CGRectMake(0, NavH, ScreenWidth, ScreenHeight-NavH)) configuration:cfg];
代理方法的处理
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message {
WS(ws)
if ([message.name isEqualToString:@"PayParam"]) {
//和h5约定好数据结构
NSDictionary *params = message.body;
//后面是相应的处理
}
}
h5:h5这边的写法就比较简单了,只需要判断手机机型,如果是苹果手机就调用相应的方法就可以了window.webkit.messageHandlers.<对象名>.postMessage(<数据>)
window.webkit.messageHandlers.PayParam.postMessage({})
二、webView页面内部的点击跳转
webView页面内可以有很多的点击事件,但不是所有的事件都是可以识别的,下面列举几种我碰到过的
1、webView做推广页面时,希望从我们的webView能跳转到商店,或者跳转到推广app(企业包)的下载地址
2、webView有电话时,希望能点击弹出提示打电话
3、h5内部可能有scheme的链接跳转
代码如下:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
NSURL *url = navigationAction.request.URL;
NSString *scheme = [url scheme];
UIApplication *app = [UIApplication sharedApplication];
// 打电话
if ([scheme isEqualToString:@"tel"]) {
if ([app canOpenURL:url]) {
[app openURL:url];
// 一定要加上这句,否则会打开新页面
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
// 打开appstore
if ([url.absoluteString containsString:@"itunes.apple.com"]) {
if ([app canOpenURL:url]) {
[app openURL:url];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
//下载企业包
if ([url.absoluteString containsString:@"itms-services://"]) {
if (@available(iOS 10.0, *)) {
[app openURL:url options:@{} completionHandler:^(BOOL success) {
}];
} else {
[app openURL:url];
}
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
webView是否打开新的url是通过这个方法来判断的
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
如果是不合法url默认返回的是WKNavigationActionPolicyCancel
,所以需要手动来处理
三、webView播放背景音乐默认没有声音
webView默认没有打开播放声音,需要手动打开
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
cfg.userContentController = userContentController;
cfg.allowsInlineMediaPlayback = YES;
if (@available(iOS 10.0, *)) {
cfg.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
}else {
cfg.mediaPlaybackRequiresUserAction = NO;
}
这些是和h5交互遇到的一些问题,以后发现新的问题再补充~
git地址:https://github.com/famile/YXBaseVCTool
跑得慢,听到的是骂声; 跑得快,听到的就只是风声