UIWebViewとWKWebViewとJSの通信
10101 ワード
概要
UIWebViewは、アプリケーションにWebコンテンツを埋め込み、対話することができますが、重くてメモリの漏洩があります.WKWebViewは、UImitのUIWebViewとAppKitのWebViewの代わりに、統合されたデュアルプラットフォームAPIを提供します.60 fpsまでのスクロールリフレッシュ率と内蔵ジェスチャーで、パフォーマンス、安定性、機能が大幅に向上し、Safariと同じJavaScriptエンジンをサポートしています.
1. UIWebView
1.1ロード方法
ロード方法は3種類ございます
1.2代理コールバック
1.3 NativeとJSの相互呼び出し
1.3.1 NativeがJSを呼び出す方法
1.3.2 JS呼び出しNativeでのメソッド
たとえば、jsでdoFooを呼び出すと、このクラスの-(void)doFoo:(id)fooメソッドが呼び出されます.
2. WKWebView
2.1ロード方法
ロード方法は4種類あり、基本的にUIWebViewと同じローカルファイルのロードが1つ増えただけです
2.2エージェントコールバック
新しいページをページにロードするかどうか
WKUIdelegate(オリジナルコントロールでWebページを表示する方法でコールバック)は、主にWKWebViewがWebインタフェースを処理する3つのヒントボックス(警告ボックス、確認ボックス、入力ボックス)に使用されます.
WKScriptMessageHandler(Webページからメッセージを受信するコールバックメソッドを提供)OCでJSの呼び出し情報を受信
2.3 NativeとJSの相互呼び出し
2.3.1 NativeがJSを呼び出す方法
2.3.2 JS呼び出しNativeでのメソッド
JSに以下のメソッドを追加して呼び出す
3.問題解決
一.WKWebViewを使用するときにdeallocでブレークポイントを打つと、解放されていないことに気づいた場合、ループリファレンスの問題(addScriptMessageHandlerメソッドで発生)が発生した可能性があります.WKScriptMessageHandlerをカスタマイズするには、weakメソッドを使用してプロキシメソッドを実装します.ページを離れるときにremoveScriptMessageHandlerForNameというメソッドを追加して削除します
二.WKWebView JSがOCを呼び出して戻り値を取得する問題-(void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)messageこのメソッドは戻り値がないので戻り値コールバックは実現できません.方法1:OC呼び出しJSメソッドロジックを借りてJS中のCallbackメソッドを再呼び出してコールバック
方法2:runJavaScriptTextInputPanelWithPromptコールバックを利用して実現できる.まず以下のコードを注入し,主にすべての呼び出しOCメソッドがpromptによって実現されることを実装する.
次にOCでPromptをキャプチャして処理してデータを返す
UIWebViewは、アプリケーションにWebコンテンツを埋め込み、対話することができますが、重くてメモリの漏洩があります.WKWebViewは、UImitのUIWebViewとAppKitのWebViewの代わりに、統合されたデュアルプラットフォームAPIを提供します.60 fpsまでのスクロールリフレッシュ率と内蔵ジェスチャーで、パフォーマンス、安定性、機能が大幅に向上し、Safariと同じJavaScriptエンジンをサポートしています.
1. UIWebView
1.1ロード方法
// UIWebView
UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
webView.delegate = self;
[self.view addSubview:webView];
// URL
NSURL *url = [[NSURL alloc] initWithString:@"http://www.biadu.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
ロード方法は3種類ございます
- (void)loadRequest:(NSURLRequest *)request; // URL
- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;// HTML
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;// NSData
1.2代理コールバック
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;// , YES,
- (void)webViewDidStartLoad:(UIWebView *)webView;//
- (void)webViewDidFinishLoad:(UIWebView *)webView;//
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;//
1.3 NativeとJSの相互呼び出し
1.3.1 NativeがJSを呼び出す方法
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
// JSFunctionName JS paramete
[self. webView stringByEvaluatingJavaScriptFromString:@"JSFunctionName('paramete')"]
1.3.2 JS呼び出しNativeでのメソッド
JS Native , UI
#importはクラスにJSPportプロトコルを追加することができ、JSPportプロトコルクラスを追加すれば、JSを通じてそのメソッド変数などを呼び出すことができます.// js oc
#define JSExportAs(PropertyName, Selector) \
@optional Selector __JS_EXPORT_AS__##PropertyName:(id)argument; @required Selector
#endif
たとえば、jsでdoFooを呼び出すと、このクラスの-(void)doFoo:(id)fooメソッドが呼び出されます.
@textblock
@protocol MyClassJavaScriptMethods
JSExportAs(doFoo,
- (NSString *)doFoo:(NSString *)foo
);
@end
@/textblock
//OC #import
@property(nonatomic,strong)JSContext *jsContext;
// JSContext
-(void)configJsContext{
if (_jsContext) return;
_jsContext = [[self contentWebview] valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSExportObject *jsExportObject = [[JSExportObject alloc] init];
jsExportObject.delegate = self;
// JSExport JSContext native doFoo -(NSString *)doFoo:(id)foo doFoo NSString
_jsContext[@"native"] = jsExportObject;
}
// OC native , js native
var s= {
methodId: i,
params: p
};
native. doFoo(JSON.stringify(s))
2. WKWebView
2.1ロード方法
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
YFMWKWebView *wkWebView = [[YFMWKWebView alloc] initWithFrame:self.view.bounds configuration:config];
wkWebView.navigationDelegate = self;
wkWebView.UIDelegate = self;
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.biadu.com"]];
[wkWebView loadRequest:mutableRequest];
ロード方法は4種類あり、基本的にUIWebViewと同じローカルファイルのロードが1つ増えただけです
//iOS 8
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
//iOS 9
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL API_AVAILABLE(macosx(10.11), ios(9.0));
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL API_AVAILABLE(macosx(10.11), ios(9.0));
2.2エージェントコールバック
3
WKNavigationDelegate(メインウィンドウのWebページのロードプロセスと新しいページのロードを行うかどうかを追跡するエージェントメソッドを提供)メインウィンドウのWebページのロードプロセスを追跡//
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
//
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
//
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
//
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
新しいページをページにロードするかどうか
//
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
}
// ,
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
decisionHandler(WKNavigationResponsePolicyAllow);
}
// ,
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
decisionHandler(WKNavigationActionPolicyAllow);
}
WKUIdelegate(オリジナルコントロールでWebページを表示する方法でコールバック)は、主にWKWebViewがWebインタフェースを処理する3つのヒントボックス(警告ボックス、確認ボックス、入力ボックス)に使用されます.
//
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
//
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
//
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;
WKScriptMessageHandler(Webページからメッセージを受信するコールバックメソッドを提供)OCでJSの呼び出し情報を受信
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
NSLog(@"JS %@ , %@",message.name, message.body);
}
2.3 NativeとJSの相互呼び出し
2.3.1 NativeがJSを呼び出す方法
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
// JSFunctionName JS paramete
[wkWebView evaluateJavaScript:@"JSFunctionName(‘paramete’)" completionHandler:^(id item, NSError * error) {
}];
2.3.2 JS呼び出しNativeでのメソッド
WKWebView JS Native
JS呼び出しNativeを行うにはWKWebViewの構成方法が必要です.Nativeでは構成情報を追加し、最後に構成されたconfigをリスト2.1
に追加する必要があります.//
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
//
WKUserContentController *controller = wkWebView.configuration.userContentController;
[controller addScriptMessageHandler:self name:@"callMe"];
Native Web JS
WKUSerScriptにカスタムJSコードを追加しconfigurationにコミットする.userContentControlで// [configuration.userContentController addUserScript:self.script]; 2.1
- (WKUserScript *)script {
if (!_script) {
NSString *jsString = @"function JSFunctionName(a) {\
var i = {\
params: a\
};\
return window.webkit.messageHandlers.callMe.postMessage(i);\
}";
// JS WKUserScript
WKUserScript *script = [[WKUserScript alloc] initWithSource:jsString
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
forMainFrameOnly:YES];
_script = script;
}
return _script;
}
JSに以下のメソッドを追加して呼び出す
// ScriptMessageHandler name,
window.webkit.messageHandlers..postMessage()
3.問題解決
一.WKWebViewを使用するときにdeallocでブレークポイントを打つと、解放されていないことに気づいた場合、ループリファレンスの問題(addScriptMessageHandlerメソッドで発生)が発生した可能性があります.WKScriptMessageHandlerをカスタマイズするには、weakメソッドを使用してプロキシメソッドを実装します.ページを離れるときにremoveScriptMessageHandlerForNameというメソッドを追加して削除します
二.WKWebView JSがOCを呼び出して戻り値を取得する問題-(void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)messageこのメソッドは戻り値がないので戻り値コールバックは実現できません.方法1:OC呼び出しJSメソッドロジックを借りてJS中のCallbackメソッドを再呼び出してコールバック
2.3
を実現するか、または使用する必要がある方法2:runJavaScriptTextInputPanelWithPromptコールバックを利用して実現できる.まず以下のコードを注入し,主にすべての呼び出しOCメソッドがpromptによって実現されることを実装する.
// [configuration.userContentController addUserScript:self.script]; 2.1
- (WKUserScript *)script {
if (!_script) {
NSString *jsString = @"function JSFunctionName(a) {\
var i = {\
params: a\
};\
return prompt('Native_'+i);\
}";
// JS WKUserScript
WKUserScript *script = [[WKUserScript alloc] initWithSource:jsString
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
forMainFrameOnly:YES];
_script = script;
}
return _script;
}
次にOCでPromptをキャプチャして処理してデータを返す
-(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {
//
if (prompt && [prompt hasPrefix:@"Native_"]) {
completionHandler( );
}else{
// promot
}
}```