iOS UIWebView小整理(四)(h5隨意調(diào)起原生頁(yè)面)

前言

APP在運(yùn)營(yíng)過(guò)程當(dāng)中,很多時(shí)候需要做一些推廣活動(dòng)類的h5,這類h5會(huì)涉及跳轉(zhuǎn)到原生的某個(gè)頁(yè)面或者需要使用某個(gè)原生已經(jīng)存在的功能。針對(duì)這種情況,很多人會(huì)說(shuō)需要先前埋點(diǎn)一些特定的交互到webview上,但有時(shí)候計(jì)劃趕不上計(jì)劃,推廣活動(dòng)有很多中類型,誰(shuí)也很難詳盡列舉需要埋點(diǎn)的交互,本著偷懶省事的原則,自己曾經(jīng)設(shè)計(jì)了一套使用(WebViewJavascriptBridge + Runtime)解決方案,整理出來(lái)僅供后來(lái)者參考。

預(yù)備知識(shí)

方案設(shè)計(jì)

sheji.png

實(shí)現(xiàn)過(guò)程

  1. webview預(yù)留監(jiān)聽(tīng)事件 clientDefineAction ,該事件可寫入自定義的webview基類當(dāng)中
  2. h5在需要交互的地方,使用WebViewJavascriptBridge傳入特定data,格式如下:
bridge.callHandler('clientDefineAction', {'type':'1','controll':'XXViewController','params':'{'xx':'xx'}'}, function(response) {});

data格式說(shuō)明:
type:int 0或1 ,調(diào)用類型, 0:方法,1:頁(yè)面
controll:string類型,需要調(diào)用的方法或者跳轉(zhuǎn)的頁(yè)面,需要ios跟android分別給到配置人員
params:string類型,客戶端需要用的參數(shù),需要ios跟android分別給到配置人員

對(duì)于controll需要傳入的參數(shù)是實(shí)體類的情況,params以以下格式返回:

'params':{'xx':'xx','entity':{'UserEntity_userInfo':{'birthday':'1988-09-09','name':'hahaha'}}

params 中key為 entity 時(shí)表明解析的json為實(shí)體類,實(shí)體類為UserEntity,在controll中的參數(shù)名稱為userInfo
可看ViewController對(duì)比理解:

params_entity.png

  1. 解析data之后,調(diào)用Runtime解析器進(jìn)行處理。

核心處理邏輯代碼

ps: 涉及公司業(yè)務(wù),已去掉部分代碼

#pragma mark ------ 監(jiān)聽(tīng)預(yù)留事件
- (void)clientDefineAction:(NSDictionary *)dict
{
    NSInteger type = [StringHelper formatterIntValue:[dict objectForKey:@"type"]];
    NSString *controllName = [dict objectForKey:@"controll"];
    NSDictionary *params = [dict objectForKey:@"params"];
    
    if (type == 0) {
        //調(diào)方法
        SEL methodsel = NSSelectorFromString([NSString stringWithFormat:@"%@:",controllName]);
       if ([self.methodHandle respondsToSelector:methodsel]) {
            //methodHandle為常用方法(微信分享、支付等)集合,需要自己整理
       }
    }else{
        //調(diào)頁(yè)面
        NSString *class = [controllName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
        
        if ([class isEqualToString:@"tab1"]) {
            //跳轉(zhuǎn)tab1
            return;
        }
        
        if ([class isEqualToString:@"tab2"]) {
            //跳轉(zhuǎn)tab2
            return;
        }
        
        if ([class isEqualToString:@"tab3"]) {
            //跳轉(zhuǎn)tab3
            return;
        }
        
        if ([class isEqualToString:@"tab4"]) {
            //跳轉(zhuǎn)tab4
            return;
        }
        
        [self findRightRoutedWithClass:class Params:params];
    }
}

runtime解析器

- (void)findRightRoutedWithClass:(NSString *)class Params:(NSDictionary *)params
{
    const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
    // 根據(jù)字符串返回類
    Class rClass = objc_getClass(className);
    if (!rClass){
        return;
    }
    // 創(chuàng)建對(duì)象
    id instance = [[rClass alloc] init];
    
    WS(weakSelf);
    if (params) {
        // 對(duì)該對(duì)象賦值屬性
        NSDictionary * propertys = params;
        [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            if ([key isEqualToString:@"entity"]) {
                //對(duì)象類型屬性
                NSDictionary *entitys = [propertys objectForKey:key];
                [entitys enumerateKeysAndObjectsUsingBlock:^(NSString *ckey, id entityObj, BOOL *s) {
                    NSArray *entityParamArray = [ckey componentsSeparatedByString:@"_"];
                    
                    if (entityParamArray.count > 0) {
                        const char *className = [entityParamArray[0] cStringUsingEncoding:NSASCIIStringEncoding];
                        Class entity = objc_getClass(className);
                        entity = [entity objectWithKeyValues:entityObj];//這里使用MJExtension解析對(duì)象
                        if ([weakSelf checkIsExistPropertyWithInstance:instance verifyPropertyName:entityParamArray[1]]) {
                            // 利用kvc賦值
                            [instance setValue:entity forKey:entityParamArray[1]];
                        }
                    }
                }];
            }else{
                //普通類型屬性
                if ([weakSelf checkIsExistPropertyWithInstance:instance verifyPropertyName:key]) {
                    // 利用kvc賦值
                    [instance setValue:obj forKey:key];
                }
            }
        }];
    }
    
    [self.currentParentVc pushNormalViewController:instance];
}

- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName
{
    unsigned int outCount, i;
    
    // 獲取對(duì)象里的屬性列表
    objc_property_t * properties = class_copyPropertyList([instance class], &outCount);
    
    for (i = 0; i < outCount; i++) {
        objc_property_t property =properties[i];
        //  屬性名轉(zhuǎn)成字符串
        NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        // 判斷該屬性是否存在
        if ([propertyName isEqualToString:verifyPropertyName]) {
            free(properties);
            return YES;
        }
    }
    
    free(properties);
    
    //這里處理UIViewController特定屬性
    if ([verifyPropertyName isEqualToString:@"title"]) {
        return YES;
    }
    
    return NO;
}

h5 關(guān)鍵js:

<script>
$(function(){
    new FastClick(document.body);
    setupWebViewJavascriptBridge(function(bridge) {
        //跳轉(zhuǎn)
        $(".shareBtn").click(function(){
//              bridge.callHandler('clientDefineAction', {'type':'1','controll':'XxxViewController','params':{'xxx':'xxx'}}, function(response) {});
//              bridge.callHandler('clientDefineAction', {'type':'1','controll':'tab1'}, function(response) {});
                bridge.callHandler('clientDefineAction', {'type':'0','controll':'shareToQQ','params':{'shareUrl': 'http://www.baidu.com','shareTitle':'奇異果子','shareDesc':'搶購(gòu)價(jià):¥0.10'}}, function(response) {});
            });         
    });
});
    
function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0);
}
</script>

最后

demo這里就不給出來(lái)了,等整理下一篇(短鏈跳轉(zhuǎn))再給,>_<//

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容