JS代码
let postMessageToApp = (json) => {
if (!json) {
throw new Error('參數不正確')
}
try {
AppModel.jumpToApp(json) // UIWebview 的调用方式,老的
//分享 AppModel.share(json)
} catch (error) {
console.log(error)
}
try {
window.webkit.messageHandlers.AppModel.postMessage(json) // WKWebview 的调用方式,新的
//分享 window.webkit.messageHandlers.AppShareModel.postMessage(json)
} catch (error) {
console.log(error)
}
}
交互代码
#import <JavaScriptCore/JavaScriptCore.h>
#import <WebKit/WebKit.h>
typedef void(^JumpToAppBlock)(NSDictionary *json);
@protocol JavaScriptObjectiveCDelegate <JSExport>
//分享
- (void)share:(NSString *)json;
//跳转
- (void)jumpToApp:(NSString *)json;
@end
@interface TWWebAppJumpBaseModel:NSObject
@property (nonatomic, weak) UIViewController *vc;
@property (nonatomic, copy) JumpToAppBlock jumpToAppBlock;
- (void)jumpToApp:(NSString *)json;
- (void)share:(NSString *)json;
@end
@interface TWWebAppJumpModel : TWWebAppJumpBaseModel <JavaScriptObjectiveCDelegate>
@property (nonatomic, weak) JSContext *jsContext;
@property (nonatomic, weak) UIWebView *webView;
@end
@interface TWWKWebJSBridgeModel:TWWebAppJumpBaseModel
@property (nonatomic, weak) WKWebView *webView;
- (void)setJSUserScriptNames:(NSArray *)userScriptNames;
- (void)removeAllUserScripts;
@end
#import "TWWebAppJumpModel.h"
@implementation TWWebAppJumpBaseModel
/**
跳轉
*/
- (void)jumpToApp:(NSString *)json{
//处理跳转
dispatch_async(dispatch_get_main_queue(), ^{
});
}
/**
分享
*/
- (void)share:(NSString *)json{
//处理分享
dispatch_async(dispatch_get_main_queue(), ^{
});
}
@end
@implementation TWWebAppJumpModel
@end
@interface TWWKWebJSBridgeModel ()<WKScriptMessageHandler>
@property (nonatomic, strong) NSArray *userScriptNames;
@end
@implementation TWWKWebJSBridgeModel
/// 注入JS MessageHandler和Name
- (void)setJSUserScriptNames:(NSArray *)userScriptNames{
if(_userScriptNames.count)[self removeAllUserScripts];
_userScriptNames = userScriptNames;
[userScriptNames enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[self.userContentController addScriptMessageHandler:self name:obj];
}];
}
/// 移除JS MessageHandler
- (void)removeAllUserScripts{
[self.userScriptNames enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[self.userContentController removeScriptMessageHandlerForName:obj];
}];
self.userScriptNames = nil;
}
/// 接收JS调iOS的事件消息
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
DLog(@"WK JS调iOS name : %@ body : %@",message.name,message.body);
NSString *body = message.body;
if ([message.name isEqualToString:@"AppModel"]) {
if (IsStrClass(body)) {
[self jumpToApp:body];
}
}else if ([message.name isEqualToString:@"AppShareModel"]) {//分享
if (IsStrClass(body)) {
[self share:body];
}
}
}
@end
UIWebView
- (TWWebAppJumpModel *)appModel{
if (!_appModel) {
_appModel = [[TWWebAppJumpModel alloc]init];
WS(weakSelf);
_appModel.jumpToAppBlock = ^(NSDictionary *json) {
};
}
return _appModel;
}
//设置jsContext
- (void)webViewContext{
self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// 通过模型调用方法。
self.jsContext[@"AppModel"] = self.appModel;
self.appModel.jsContext = self.jsContext;
self.appModel.webView = self.webView;
self.appModel.vc = self;
self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
DLog(@"异常信息:%@", exceptionValue);
};
}
#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView{
[self webViewContext];
}
WKWebView
- (TWWKWebJSBridgeModel *)jsBridgeModel{
if (!_jsBridgeModel) {
_jsBridgeModel = [[TWWKWebJSBridgeModel alloc]init];
WS(weakSelf);
_jsBridgeModel.jumpToAppBlock = ^(NSDictionary *json) {
};
}
return _jsBridgeModel;
}
- (WKWebView *)createWKWebView{
//设置网页的配置文件
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];
//允许视频播放
if (IOS_Versions >= 9.0) {
configuration.allowsAirPlayForMediaPlayback = YES;
if ([self isUseWKCacheStore]) {
configuration.websiteDataStore = [WKWebsiteDataStore defaultDataStore];
}
}
configuration.preferences.javaScriptEnabled = YES;
configuration.preferences.javaScriptCanOpenWindowsAutomatically = NO;
// 允许在线播放
configuration.allowsInlineMediaPlayback = YES;
// 允许可以与网页交互,选择视图
configuration.selectionGranularity = YES;
// web内容处理池
configuration.processPool = [[WKProcessPool alloc] init];
configuration.suppressesIncrementalRendering = NO;
// 通过JS与webview内容交互
configuration.userContentController = [[WKUserContentController alloc] init];
self.jsBridgeModel.userContentController = configuration.userContentController;
self.jsBridgeModel.vc = self;
[self.jsBridgeModel setJSUserScriptNames:@[@"AppModel",@"AppShareModel"]];
// 允许用户更改网页的设置
WKWebView *prewkwebview = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
if (IOS_Versions >= 9.0) {
NSString *agent = [USER_DEFAULTS objectForKey:@"UserAgent"];
if(![HouseValidateTool isEmpty:agent]){
prewkwebview.customUserAgent = agent;
}
}
prewkwebview.navigationDelegate = self;
prewkwebview.scrollView.delegate = self;
prewkwebview.UIDelegate = self;
self.jsBridgeModel.webView = prewkwebview;
return prewkwebview;
}
- (void)dealloc{
[self.jsBridgeModel removeAllUserScripts];
}
//在JS端调用alert函数时,会触发此代理方法。
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
//JS端调用confirm函数时,会触发此方法
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
//JS端调用prompt函数时,会触发此方法
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;
UIWebView 及 WKWebView执行js函数
//执行js 函数
- (void)executejsContext:(NSString *)context{
WS(weakSelf);
if ([self isShowWKWebView]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.wkwebview evaluateJavaScript:context completionHandler:^(id _Nullable response, NSError * _Nullable error) {
DLog(@"response: %@ error: %@", response, error);
}];
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.jsContext && context) {
[weakSelf.jsContext evaluateScript:context];
}
});
}
}
- WKWebview的js与客户端交互回调函数didReceiveScriptMessage 是在主线程中
- UIWebview的js与客户端的回调函数是实现JSExport协议的方法是在子线程中所以不是线程安全
Thanks
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub Issues