UIWebview交互之自定義傳值跳轉

UIWebview經常會用到和原生頁面的跳轉,有的可能還需要傳值跳轉。自己寫了一個自定義跳轉的webview,可以跳轉到指定控制器並傳值,這需要和後臺協商好,html中如何傳值跳轉,即:html中的跳轉按鈕關聯的js方法如何書寫。

html中的書寫

html中的測試代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<script type="text/javascript">
    //以下爲寫死的數據直接跳轉,原則上後臺能動態的給出對應的值並通過點擊事件傳值到原生方法中,達到傳值並跳轉原生頁面的效果。
    //controllerName對應的名字爲原生頁面控制器的類名
    //controllerProperties則是字典,包含了上面控制器對應的屬性名和值,相當於鍵值對,即需要傳給原生頁面的值
    //A控制器需要傳的值
    var controllerNameA = "AViewController";
    var controllerPropertiesA = { "prodId": "1001", "prodName": "吸塵器", "prodPrice": "50元" };
    //B控制器需要傳的值
    var controllerNameB = "BViewController";
    var controllerPropertiesB = { "petId": "1002", "petName": "趴趴熊", "petPrice": "100萬" };
    //C控制器需要傳的值
    var controllerNameC = "CViewController";
    var controllerPropertiesC = { "personId": "1003", "personName": "Tom", "personSex": "變態" };
    //這裏定義了跳轉方法,點擊事件會執行下面的方法並傳至給原生方法
    function jumpToController(controllerName,controllerProperties) {
    }
</script>
<body bgcolor="#555555">
    <!--下面爲3個跳轉到對應頁面的按鈕-->
<button type="button"  onclick="jumpToController(controllerNameA,controllerPropertiesA)">點擊傳至並跳轉到A控制器</button>
<button type="button"  onclick="jumpToController(controllerNameB,controllerPropertiesB)">點擊傳至並跳轉到B控制器</button>
<button type="button"  onclick="jumpToController(controllerNameC,controllerPropertiesC)">點擊傳至並跳轉到C控制器</button>
</body>
</html>

上面的jumpToController方法即爲跳轉方法,點擊按鈕後會對應的把值傳到方法中並執行大括號內種的內容,內容裏面什麼都沒有,這並不重要,我們的目的只是把值傳到方法裏,原生頁面通過JavaScriptCore可以知道執行了這個方法和傳過來的值足已,因爲跳轉頁面只需要控制器名和對應的屬性值。


原生頁面中

  • 首先需要定義3個控制器。

    AViewController,BViewController,CViewController,裏面定義好測試的屬性(其實應該是先做的控制器,html根據原生頁面的具體類名和屬性來傳值),這裏我們以A屬性爲例:

#import <UIKit/UIKit.h>

@interface AViewController : UIViewController
@property(nonatomic, copy) NSString *prodId;
@property(nonatomic, copy) NSString *prodName;
@property(nonatomic, copy) NSString *prodPrice;
@end
  • 控制器中m文件輸出數據。

    在進入頁面後打印這些屬性,如果最後有值傳過來,那麼打印出來的肯定不是空值。

#import "AViewController.h"

@interface AViewController ()

@end

@implementation AViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"A";
    self.view.backgroundColor = [UIColor grayColor];
    NSLog(@"屬性分別是prodId:%@,prodName:%@,prodPrice:%@", self.prodId, self.prodName, self.prodPrice);
    // Do any additional setup after loading the view.
}
  • 初始頁面添加JSContext屬性並加載html文件。

    這裏加載之前寫的那個html文件:

#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import <objc/Runtime.h>

@interface ViewController () <UIWebViewDelegate>
@property(nonatomic, weak) IBOutlet UIWebView *webView;
@property(nonatomic, weak) JSContext *context;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self webViewConfig];
    // Do any additional setup after loading the view, typically from a nib.
}

/**設置本地網頁,並讀取之*/
- (void)webViewConfig {
    self.title = @"初始網頁";
    NSString *path = [[NSBundle mainBundle] pathForResource:@"jstest" ofType:@"html"];
    NSLog(@"%@", path);
    NSURL *url = [[NSURL alloc] initFileURLWithPath:path];
    NSLog(@"%@", url);
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    self.webView.delegate = self;
    [self.webView loadRequest:request];
}
  • 關鍵點,獲取到全局的js環境並拿到值進行跳轉。需要寫在webViewDidFinishLoad裏,代碼如下:
/**設置JS環境,這裏需要在網頁讀取之後*/
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    /**獲取全局的js環境*/
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    /**描述html裏的方法jumpToController如何執行*/
    self.context[@"jumpToController"] = ^{
        /**args爲獲取這個方法傳過來的參數,得到的是JSValue對象,和後臺協商好,傳過來就只有一個字符串和一個字典,字符串放控制器名稱,字典的key和value對應屬性名和其值*/
        NSArray *args = [JSContext currentArguments];
        Class controllerClass = nil;
        NSDictionary *parameters = nil;
        /**遍歷從js傳過來的值,這裏只有兩個,一個字符串一個字典,字符串爲類名,字典爲需要的屬性*/
        for (JSValue *jsVal in args) {
            /**傳過來的值是字符串,說明是控制器名字*/
            if ([jsVal isString]) {
                NSString *controllerName = [jsVal toString];
                controllerClass = NSClassFromString(controllerName);
            }
            /**傳過來的值是對象,說明存的是參數,那麼使用字典接收*/
            if ([jsVal isObject]) {
                parameters = [jsVal toDictionary];
            }
        }
        /**拿到類名和屬性,直接生成控制器賦值(務必保證傳過來的字符串是正確的控制器類名)*/
        UIViewController *viewController = (UIViewController *) [[controllerClass alloc] init];//既然已經是傳的正確的控制器名,那麼這裏一定可以強轉成功。
        /**給控制器賦值*/
        [viewController setValuesForKeysWithDictionary:parameters];
        /**頁面跳轉*/
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.navigationController pushViewController:viewController animated:YES];
        });
    };
}
  • A界面進入後,顯示打印結果,即爲html中傳的值。(請忽略界面不是xcode細節)。
    這裏寫圖片描述

原則上來講,html中的傳值,是一樣可以做到動態傳的,也即是說可以動態傳值跳轉,這個demo其實可以進一步進行封裝,加上加載條等,作爲一個基礎網頁控制器。
demo下載地址:https://github.com/JeffreyWW/JFJSCoreTest
歡迎交流,QQ:25105483

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章