關(guān)于iOS中原生和h5交互的知識總結(jié)(一) UIWebView

前言

第一次寫簡書,本人是從事iOS開發(fā)工作的意推,由于工作中經(jīng)常涉及一些原生和h5交互的知識驶兜,再加上領(lǐng)導的建議,特來總結(jié)一下開發(fā)過程中所涉及的知識和坑俊扳。

目錄

關(guān)于iOS中原生和h5交互的知識總結(jié)(一)UIWebView
關(guān)于iOS中原生和h5交互的知識總結(jié)(二)WKWebView

基于UIWebView的實現(xiàn)途蒋,請注意以下幾點

1.模型注入
2.注入時機*

樣例

負責與js交互的工具類
JSHandler.h

#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>

@protocol JSHandlerProtocol <JSExport>

/*
    多參數(shù)的方法
    由于涉及到多參數(shù)的問題,從第二個參數(shù)開始馋记,外部參數(shù)名都要使用大寫開頭
    因為JS調(diào)用OC方法時号坡,是將OC方法拼接連成字符串,如果無法區(qū)分就會造成無法識別
    比如對于下面的OC方法梯醒,JS調(diào)用時
    javascript.sayHelloToWithGreeting(參數(shù)1宽堆,參數(shù)2) //正確寫法
    javascript.sayHelloTowithGreeting(參數(shù)1,參數(shù)2) //錯誤寫法(就是注意大小寫啦)
*/

//- (void)sayHelloTo:(NSString *)name WithGreeting:(NSString *)greeting;

#pragma mark - methods for js

/**
 js端要傳參茸习,調(diào)用native端的加密方法
 */
- (NSString *)aesEncryptString:(NSString *)text;

/** 
 js端要傳參畜隶,調(diào)用native端的解密方法
 */
- (NSString *)aesDecryptString:(NSString *)text;


/**
 js端不傳參,調(diào)用native端獲取token
 */
- (NSString *)getToken;


/**
 js端調(diào)用客戶端号胚,顯示登錄界面籽慢,無返回值
 */
- (void)showLoginScene:(NSString *)message;

@end

@interface JSHandler : NSObject<JSHandlerProtocol>

@end

JSHandler.m

#import "JSHandler.h"
#import "LocalSaveManager.h"
#import <JavaScriptCore/JavaScriptCore.h>

@implementation JSHandler:NSObject

#pragma mark - 實現(xiàn)代理方法
- (NSString *)aesEncryptString:(NSString *)text
{
    
}

- (NSString *)aesDecryptString:(NSString *)text
{
    
}

- (NSString *)getToken
{
   
}

- (void)showLoginScene:(NSString *)message
{
  
}

使用JSHandler
HomeViewController.m

#import <JavaScriptCore/JavaScriptCore.h>
#import "JSHandler.h"
#import "NSObject+JSContextTracker.h"

static NSString *const JSContextObject = @"jsHandler";
@interface HomeViewController ()
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@property (nonatomic, strong) JSContext *jsContext;
@property (nonatomic, strong) JSHandler *jsHandler;

@end

@implementation HomeViewController

/*
可能大多數(shù)人都會這樣使用,這里為了引出“注入時機”的問題涕刚,先演示個常規(guī)寫法嗡综,在viewDidLoad里注入jsHandler對象。
并不是說在viewDidLoad時注入jsHandler不對杜漠,而是這樣會有注入時機的問題极景。比如在js加載時我們就去native端獲取token察净,
而不是去點擊某個按鈕才去獲取token。這時JSContext還沒有創(chuàng)建完畢盼樟,但是我們?nèi)毕騄SContext中注入jsHandler對象氢卡,
所以當在js端使用jsHandler對象時會報找不到jsHandler這個對象的錯誤!
*/

/*
 有的同學會想如果在webView的這兩個代理方法中注入jsHandler對象是否是正確的時機呢
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
答案是否定的晨缴,webViewDidStartLoad時JSContext還沒有創(chuàng)建译秦,webViewDidFinishLoad看似是頁面已經(jīng)加載完的回調(diào),
但這時JSContext真的有創(chuàng)建完畢嗎击碗,肯能有些同學發(fā)現(xiàn)在webViewDidFinishLoad時筑悴,當你切換html頁面的時候,
有時候能找到jsHandler對象稍途,有時不能找到阁吝,暈!JSContext對象創(chuàng)建完成械拍,注入jsHandler對象真的是一個很微妙的時機突勇,
并且webView那少的可憐的幾個代理方法真的不能解決我們的問題,腫么辦坷虑,往下看甲馋!
*/
- (void)viewDidLoad {
    [super viewDidLoad];
    self.jsHandler = [JSHandler new];
    self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.jsContext[JSContextObject] = self.jsHandler;
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
        context.exception = exceptionValue;
        NSLog(@"異常信息:%@", exceptionValue);
    };
}

還記得我們引入了#import "NSObject+JSContextTracker.h"這個頭文件嗎,這是個關(guān)鍵的類目啊迄损,現(xiàn)在給出這個類目的實現(xiàn)
NSObject+JSContextTracker.h


#import <Foundation/Foundation.h>

static NSString *const JSContextTrackerNotifycation = @"JSContextTrackerNotifycation";
@interface NSObject (JSContextTracker)

@end

NSObject+JSContextTracker.m

#import "NSObject+JSContextTracker.h"
#import <JavaScriptCore/JavaScriptCore.h>
@implementation NSObject (JSContextTracker)
/*
這個類目在創(chuàng)建JSContext對象時會發(fā)出一個通知定躏,這個類目不需要我們主動去調(diào)用,在JSContext對象創(chuàng)建時會自動調(diào)用海蔽,
至于比較偏底層的原理共屈,網(wǎng)上也有介紹绑谣,感覺都是東一塊西一塊党窜,要不就是英文翻譯過來的,看了之后也不是特別理解借宵。
由于我本人理解的也是有些模糊幌衣,在此就不解釋原理的,怕誤導大家壤玫,如果之后我弄清楚了豁护,會及時更新的。
感興趣的朋友也可以網(wǎng)上自行去找找資料欲间,如果弄清楚了可以留言楚里,幫助我和大家解惑,謝謝啦
*/
- (void)webView:(id)unused didCreateJavaScriptContext:(JSContext *)context forFrame:(id)alsoUnused {
    if (!context)
        return;
    [[NSNotificationCenter defaultCenter] postNotificationName:JSContextTrackerNotifycation object:context];
}

@end

現(xiàn)在給出HomeViewController.m最佳注入jsHandler對象的時機

#import <JavaScriptCore/JavaScriptCore.h>
#import "JSHandler.h"
#import "NSObject+JSContextTracker.h"

static NSString *const JSContextObject = @"jsHandler";
@interface HomeViewController ()
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@property (nonatomic, strong) JSContext *jsContext;
@property (nonatomic, strong) JSHandler *jsHandler;

@end

@implementation HomeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.jsHandler = [JSHandler new];
    NSString *url = @"";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadRevalidatingCacheData timeoutInterval:60];
    [self.webView loadRequest:request];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(createJSContext:) name:JSContextTrackerNotifycation object:nil];
}

/*
  現(xiàn)在createJSContext中就是注入jsHandler對象的最佳時機
*/
-(void)createJSContext:(NSNotification*)notification
{
    //注意以下代碼如果不在主線程調(diào)用會發(fā)生閃退猎贴。
    dispatch_async( dispatch_get_main_queue(), ^{
    
        self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        self.jsContext[JSContextObject] = self.jsHandler;
        
        self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
            context.exception = exceptionValue;
            NSLog(@"異常信息:%@", exceptionValue);
        };
    });
}

最后給出js端的代碼班缎,是如何調(diào)用原生的蝴光,把他作為工具類,專門處理和native交互
native-tool.js

function isAndroid() {
    var u = navigator.userAgent;
    var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
    return isAndroid;
}

function isIOS() {
    var u = navigator.userAgent;
    var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
    return isIOS;
}

//得到native端token
function native_getToken() {
    var token;
    if (isIOS()) {
        token = jsHandler.getToken();
    } else if (isAndroid()) {
        token = contact.getToken();
    }

    return token;
}

//顯示登錄界面
function native_showLoginScene(message) {

    if (isIOS()) {
        jsHandler.showLoginScene(message);
    } else if (isAndroid()) {
        contact.showLoginScene(message);
    }
}

//調(diào)用native加密
function native_encrypt(str) {
    var res;
    if (isIOS())
    {
        res = jsHandler.aesEncryptString(str);
    } 
    else if (isAndroid())
    {
        res = contact.encrypt(str);
    }
    return res;
}

UIWebView js和原生交互結(jié)束語

這里只介紹了“模型注入”的方式达址,并且填了“注入時機“這個坑蔑祟,因為UIWebView暴露給我們的方法太少了,而且iOS11中沉唠,UIWebView已經(jīng)不推薦使用了疆虚,所以接下來我們著重介紹iOS的負責web顯示的新寵兒WKWebView

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市满葛,隨后出現(xiàn)的幾起案子径簿,更是在濱河造成了極大的恐慌,老刑警劉巖嘀韧,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牍帚,死亡現(xiàn)場離奇詭異,居然都是意外死亡乳蛾,警方通過查閱死者的電腦和手機暗赶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肃叶,“玉大人蹂随,你說我怎么就攤上這事∫虿眩” “怎么了岳锁?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蹦魔。 經(jīng)常有香客問我激率,道長,這世上最難降的妖魔是什么勿决? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任乒躺,我火速辦了婚禮,結(jié)果婚禮上低缩,老公的妹妹穿的比我還像新娘嘉冒。我一直安慰自己,他們只是感情好咆繁,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布讳推。 她就那樣靜靜地躺著,像睡著了一般玩般。 火紅的嫁衣襯著肌膚如雪银觅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天坏为,我揣著相機與錄音究驴,去河邊找鬼慨仿。 笑死,一個胖子當著我的面吹牛纳胧,可吹牛的內(nèi)容都是我干的镰吆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼跑慕,長吁一口氣:“原來是場噩夢啊……” “哼万皿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起核行,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤牢硅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后芝雪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體减余,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年惩系,在試婚紗的時候發(fā)現(xiàn)自己被綠了位岔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡堡牡,死狀恐怖抒抬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晤柄,我是刑警寧澤擦剑,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站芥颈,受9級特大地震影響惠勒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜爬坑,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一纠屋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妇垢,春花似錦巾遭、人聲如沸肉康。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吼和。三九已至涨薪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炫乓,已是汗流浹背刚夺。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工献丑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侠姑。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓创橄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親莽红。 傳聞我的和親對象是個殘疾皇子妥畏,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 這篇文章發(fā)于2017/03/08 “第七島”原創(chuàng)公眾號 現(xiàn)在在“簡書”補充發(fā)布 我將與shasha(我的小老板)一...
    Sun渣婷閱讀 347評論 0 0
  • 驚聞我友煥蓮離世,甚是惋惜安吁。嗚呼醉蚁!為何人生無常,天妒英才鬼店? 剛過五十网棍,上要孝親,下要育兒妇智,她如此抽身離去滥玷,怎能忍心...
    喵喵喵喵寶閱讀 607評論 0 2
  • 我一閨蜜小A,是個濃眉大眼樂觀開朗的女孩巍棱,富有靈性罗捎。眼角眉稍,笑意流轉(zhuǎn)拉盾,仿佛哪怕全世界就只剩下她一個桨菜,也能自嗨起來...
    小竹筏兒閱讀 509評論 1 2
  • 認識“馬云",身邊的朋友都說我是奔著他響亮的名字去的捉偏,這讓我很無語倒得。第一,認識他的時候我并不知道他姓啥叫誰;第二夭禽,...
    十月城池閱讀 530評論 4 7
  • 熱水打在身上霞掺,臉上,順著頭發(fā)滑落讹躯,滴滴答答的水流從發(fā)尖摔落地板磚上菩彬,濺開了無數(shù)的水花,迫不及待落下潮梯,無聲勝有聲...
    簡曉愛閱讀 212評論 0 0