項目中需要用到與H5端的JS交互,總結一下用法:
ios的 js 交互分為兩塊:
一、OC調用JS
這一塊實現起來比較簡單,一句代碼搞定:
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//首先創建JSContext對象、獲取當前JS運行環境
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//無參的情況
NSString *js1 = @"appMethod1()";
[context evaluateScript:js1];
//只有一個參數的情況
NSString *js2 = @"appMethod2('參數')";
[context evaluateScript:js2];
//多個參數的情況
NSString *js = [NSString stringWithFormat:@"appMethod3('%@','%@')",參數A,參數B];
[context evaluateScript:js3];
//注:[webView stringByEvaluatingJavaScriptFromString:js]
與 [context evaluateScript:js]的功能的一樣的;
}
后來項目中用到OC調用JS方法并傳參的時候,發現上面的方法并不起作用,原因至今未找到,后來又找到了下面的方法可行:
-(void)webViewDidFinishLoad:(UIWebView *)webView{
//首先創建JSContext對象、獲取當前JS運行環境
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSValue *value = context[@"uploadPortrait"];
[value callWithArguments:@[self.base64Image,self.imageName]];//兩個參數
[value callWithArguments:@[nil]];//無參的情況
}
注:OC調用JS的代碼不一定寫在webViewDidFinishLoad里面,可根據需要,寫在所需的位置
二、JS調用OC
第一種情況: js端直接調用方法(block)
//其中test1就是js的方法名稱,賦給是一個block 里面是iOS代碼
//此方法最終將打印出所有接收到的參數,js參數是不固定的 我們測試一下就知道
-(void)webViewDidFinishLoad:(UIWebView *)webView{
//首先創建JSContext對象、獲取當前JS運行環境
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//將我們的context對象與js方法建立橋接聯系,
context[@"test1"] = ^() {
NSArray *arguments = [JSContext currentArguments];
for (id obj in arguments) {
NSLog(@"%@",obj);
}
};
}
//首先準備一下js代碼,來調用js的函數test1 然后執行
NSString *jsFunctStr=@"test1('參數1')";
[context evaluateScript:jsFunctStr];
}
第二種情況:JS端通過對象調用(常用方法)
1、說到對象調方法我們首先肯定得有個對象,所以我們首先需要在OC端創建一個js交互類,并聲明和實現相應的交互方法,
2、需要在這個自定義交互類里面導入JavaScriptCore框架
3、聲明一個遵從于JSExport協議的協議(有點繞,看圖),在這個協議里聲明我們的交互方法(需要與JS端商定好方法名)
JSObjectUtil.h文件
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h> //引入頭文件
#import "JXPayViewVC.h"http://支付
#pragma mark - 聲明JS交互的協議,遵從于JSExport協議
//JSObjectDelegate為協議名
@protocol JSObjectDelegate <JSExport>
#pragma mark - JS調用OC的方法,此方法名與網頁端溝通 必須名字相同
//payOrder...這個方法沒有,這個方法的作用是當js端的方法有兩個或兩個以上參數時,
//我們需要讓- (void)payOrder:(NSString*)str appID:(NSString*)appID這個方法代替 “payForApp”這個方法,因為oc端的方法名必須和js端的保持一致,不然就不會被調用,如下:
JSExportAs(payForApp, - (void)payOrder:(NSString*)str appID:(NSString*)appID);
//此外,也可以自己拆分方法名,如:payForApp---->pay:xxx For:xxx App:xxx
//調用支付寶、微信支付(下面為OC端方法)
-(void)pay:(NSString *)params For:(NSString *)backParams App:(NSString *)payOrg;
@end
#pragma mark - 讓我們創建的類實現上邊的協議
@interface JSObjectUtil : NSObject<JSObjectDelegate>
//這里的payMoney可以用來直接調用JXPayViewVC類里面的任何方法
@property(nonatomic,strong)JXPayViewVC *payMoney;
@end
JSObjectUtil.m文件
#import "JSObjectUtil.h"
@implementation JSObjectUtil
//支付
//1、payForApp()是OC端的方法名,含有三個參數,因此需要對payForApp進行拆分加參數
//2、是通過OC端調用JS端的appMethod方法,同時JS端在appMethod方法里面套入需要調用OC端的方法名進行調用
//3、OC 端可以在被JS端調用的方法里面,讓遵從交互協議類的對象調用此類里面的方法
-(void)pay:(NSString *)params For:(NSString *)payID App:(NSString *)payOrg
{
NSLog(@"JS調用了OC的payForApp方法");
//self.payMoney對象調用JXPayViewVC類的方法
[self.payMoney sendPay:params payID:payID payOrder:payOrg];
}
@end
加載webView頁面類的.m文件
-(void)webViewDidFinishLoad:(UIWebView *)webView{
//加載JS交互
[self loadJSObject:webView];
}
-(JSContext *)loadJSObject:(UIWebView *)webView{
//1、首先創建JSContext對象、獲取當前JS運行環境
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//2、創建模型來調用方法
JSObjectUtil *jsUtil = [JSObjectUtil new];
jsUtil.payMoney = self;//讓我們的交互類遵從協議
//3、注入JS對象,其中"AppFunLoader"是JS的對象名,需要與JS端商定好名稱,用它來調用下面的pay的appMethod方法
context[@"AppFunLoader"] = jsUtil;
//4、開始調用JS端的appMethod方法
NSString *pay = @"appMethod()";
[context evaluateScript:pay];
return context;
}