淺談JS代碼和OC代碼的交互

以下為個人愚見, 如有不妥,望大家斧正!!!
本文的GitHub源碼下載地址:
https://github.com/DXSmile/JS-OC.git

如需轉載,請注明轉載自DXSmile的
GitHub項目https://github.com/DXSmile/JS-OC.git

簡述:

隨著應用開發(fā)技術的日漸更新迭代, 特別是HTML5出來之后, 現在很多的移動端應用開發(fā)也越來越趨向于使用HTML5的技術來設計和完成相對復雜的UI頁面設計和交互, 就像之前我又一篇文章寫的一樣,
HTML5很可能就是下一個技術的焦點, 很多的語言,平臺,都將會更加兼容HTML5技術,企業(yè)也將會越來越多的使用HTML5, 那么作為一名iOS移動開發(fā)攻城獅來說, 我們就需要不斷的學習成長,盡快弄精通HTML5和OC,和swift的交互,從而來實現更多更新的技術;
前文鏈接如下:
你不得不了解,甚至立馬學習的HTML5

今天我就來和大家簡單的說一下HTML5中,JS代碼和OC代碼的交互, 由于時間關系,我這里只做簡單的描述,具體深入的交互,需要大家后面不斷的練習;

JS和OC的交互方式簡單來說有兩種情況:

交互前提: 在OC端使用webView!!!

1.OC調用JS - OC執(zhí)行JS代碼

步驟1> 顯示頁面,其實就是加載請求 :
使用 [self.webView loadRequest:request];
并且讓控制器成為webView的代理, 監(jiān)聽網頁加載完畢 : 使用<UIWebViewDelegate>的代理方法:

/**
 *  網頁加載完畢
 */
- (void)webViewDidFinishLoad:(UIWebView *)webView { }

步驟2> 讓頁面調用OC中的腳本,它屬于webView的一個方法,特別提醒 : 執(zhí)行JS腳本代碼僅僅只有這一種方法:

       [webView stringByEvaluatingJavaScriptFromString:@“JS代碼”];

舉例 一:

/**
 *  網頁加載完畢
 */
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    NSString *js = @"document.getElementsByTagName('footer')[0].remove();";
    [webView stringByEvaluatingJavaScriptFromString:js];
}

舉例 二:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    NSString *JS代碼 = @"function login (username, pwd) {  "
                    "   return 10;"
                    "       }"
                    "   login();";
   //     在OC中調用JS的函數(執(zhí)行JS代碼)
   [webView stringByEvaluatingJavaScriptFromString:@“JS代碼”];
}

2. JS調用OC - 就是JS調用OC中的方法

步驟1> 需自定義href協議,可以指定方法名和參數 : 然后將OC方法和參數值拼接在一個URL中
如下: 自定義href協議

  NSString *onload = @"this.onclick = function() {"
       1> 打電話方法,有參數    "window.location.href = 'dx:call:&10086'"
       2> 發(fā)信息方法,有參數    "window.location.href = 'dx:sendMsg:&10010'"
       3> 關機方法,無參數      "window.location.href = 'dx:shutdown'"
                                "};";
[imgHtml appendFormat:@"<img onload=\"%@\" width=\"%d\" height=\"%d\" src=\"%@\"><div>",onload,width , height, img.src];

將OC方法和參數值拼接在一個URL中:

/*  通用url的設計
    1> 找一個固定的協議: 如  dx:
    2> 一般有2個參數   2.1> 方法名  2.2> 方法參數
*/
      window.location.href = 'dx:saveImageToAblum:&' + this.src

步驟2> 使用<UIWebViewDelegate>代理協議中的方法攔截請求 : 每次發(fā)送請求之前系統(tǒng)會自動調用該代理方法:

/**
    調用 : 每當webView發(fā)送一個請求之前都會先調用這個方法
參數說明:
    request : 即將發(fā)送的請求
    BOOL : Yes : 允許發(fā)送這個請求  No : 禁止發(fā)送這個請求
    navigationType : 是否在新窗口中打開
 */
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//        a) 在這個代理方法中攔截JS請求的URL
//        b) 從URL中截取相應的方法名和參數
//        c) 調用方法虐先,傳遞參數
 
      return YES/NO;
}
小結: 通常情況來說, JS和OC的交互,就是上面兩種情況, 理清思路,就可以很好的做好交互了;接下來就是需要寫代碼了;

下面我附上一份我自己寫的代碼:

#pragma mark - 發(fā)送get請求 獲取數據
/** 發(fā)送get請求,獲取新聞的詳情 */
- (void)getUpData {
    // 測試地址: http://c.m.163.com/nc/article/{docid}/full.html  
    NSString *url = [NSString stringWithFormat:@"http://c.m.163.com/nc/article/%@/full.html", self.headline.docid];
    
    [[DXHTTPManager manager] GET:url parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary *responseObject) {
        [responseObject writeToFile:@"/Users/xiongdexi/Desktop/Data/newsDetail.plist" atomically:YES];
       
        // 根據對應的docid賦值
        self.detailNews = [DXDetail detailWithDict:responseObject[self.headline.docid]];
        
        // 顯示到webView上
        [self showDetailForWebView];

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"加載出錯, %@", error);
    }];
    
}

接下來需要拼接html代碼:

#pragma mark - 拼接html,顯示數據到webView上
 /** 顯示到webView上 */
- (void)showDetailForWebView {
    // 1.初始化一個可變字符串
    NSMutableString *html = [NSMutableString string];
    // 2.拼接html代碼
    [html appendString:@"<html>"];
    // 2.1 頭部內容
    [html appendString:@"<head>"];
    
    // 引入css文件
    NSURL *path = [[NSBundle mainBundle]URLForResource:@"DXDetail.css" withExtension:nil];
    [html appendFormat:@"<link rel=\"stylesheet\" href=\"%@\">", path];

    [html appendString:@"</head>"];
    
    // 2.2 具體內容
    [html appendString:@"<body>"];
    
    // 將圖片插入插入body對應的標記中
    [html appendString:[self setupBody]];
    
    [html appendString:@"</body>"];
    
    // 2.3 尾部內容
    [html appendString:@"</html>"];
    
    // 3. 顯示網頁
    [self.webView loadHTMLString:html baseURL:nil];
    
}

/** 拼接body的內容  (也就是初始化body內容) */
- (NSString *)setupBody {
    
    NSMutableString *bodyM = [NSMutableString string];
    
    
    // 拼接標題
    [bodyM appendFormat:@"<div class=\"title\">%@</div>", self.detailNews.title];
    
    // 拼接時間
    [bodyM appendFormat:@"<div class=\"time\">%@</div>",self.detailNews.ptime];
    
    // 拼接圖片  img.ref ==  <!--IMG#0-->  <!--IMG#0--> --> <img src=img.src>
    [bodyM appendString:self.detailNews.body];
    
    for (DXDetailImg *img in self.detailNews.img) {
        NSMutableString *imgHtml = [NSMutableString string];
        
        // 定義圖片的寬高比 550*344  用下面的方法切割尺寸字符串
        NSArray *pixel = [img.pixel componentsSeparatedByString:@"*"];
        int width = [[pixel firstObject] intValue];
        int height = [[pixel lastObject] intValue];
        int maxWidth = [UIScreen mainScreen].bounds.size.width * 0.8;
        // 限制寬度
        if (width > maxWidth) {
            height = height * maxWidth / width; // 數學計算,等比例公式
            width = maxWidth;
        }
        
        // 拼接圖片
        [imgHtml appendString:@"<div class=\"img-parent\">"];
        
        // 給圖片綁定點擊事件onclick
        // 注意這里需要先定義一個虛假的協議標記, 讓webView不執(zhí)行跳轉,而是只獲取圖片的url
        // 為了預防圖片太大,沒有加載完成就調用了下面的保存方法,可以添加一個限制,用onload來限制讓圖片下載完成之后再執(zhí)行保存
        NSString *onload = @"this.onclick = function() {"
                            "window.location.href = 'dx://?src=' + this.src;"
                            "};";
        
        [imgHtml appendFormat:@"<img onload=\"%@\" width=\"%d\" height=\"%d\" src=\"%@\">",onload, width, height, img.src];
        
        [imgHtml appendString:@"</div>"];
        
        // 用一個字符串代替另一個字符串   這樣就可以讓標記圖片注釋的部位用一張真正的圖片來替代
        [bodyM replaceOccurrencesOfString:img.ref withString:imgHtml options:NSCaseInsensitiveSearch range:NSMakeRange(0, bodyM.length)];
    }
    return bodyM;
}

CSS代碼: DXDetail.css文件

.title {
    text-align : center;
    font-size : 25px;
    color : black;
    font-weight : 5px;
}

.time {
    text-align :center;
    font-size : 15px;
    color :gray;
    margin-top : 5px;
    margin-bottom : 10px;
}

.img-parent {
    text-align :center;
}

JS與OC代碼的交互:

#pragma mark - 用戶點擊圖片后的事件 JS與OC代碼的交互
/** 當用戶點擊圖片時,彈出提示框 并將圖片保存到相冊 */
// 這里需要用到JS代碼和OC代碼的交互
- (void)saveImageToAlbum:(NSString *)imgSrc {
    
    // 1. 提示一個彈窗,提示用戶是否需要保存圖片
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"溫馨提示" message:@"您是否需要將圖片保存到相冊?" preferredStyle:UIAlertControllerStyleActionSheet];
    // 1.1 添加兩個按鈕到彈窗上
    [alert addAction:[UIAlertAction actionWithTitle:@"是的" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        // 保存圖片到相冊
        [self saveToAlbum:imgSrc];
    }]];
    
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
    
    // 1.2 顯示
    [self presentViewController:alert animated:YES completion:nil];

}

/** 保存圖片到相冊的代碼封裝 */
- (void)saveToAlbum:(NSString *)imgSrc {
    // UIWebView 的緩存由 NSURLCache 來管理
    // 獲取緩存對象
    NSURLCache *cache = [NSURLCache sharedURLCache];
    // 在緩存中取得對應請求的圖片
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imgSrc]];
    NSCachedURLResponse *response = [cache cachedResponseForRequest:request];
    NSData *imageData = response.data;
    
    // 保存圖片
    UIImage *image = [UIImage imageWithData:imageData];
    // 調用保存到相冊的方法 后面三個參數為空,表示保存之后什么都不做
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);

}

執(zhí)行<UIWebViewDelegate>的代理方法

#pragma mark - 實現<UIWebViewDelegate>的代理方法
// 調用webView的代理方法之一: 每當webView發(fā)送一個請求之前就會先執(zhí)行一次的方法
// 返回值: YES 表示允許發(fā)送請求, NO表示不允許發(fā)送請求
// 在webView的代理方法中截取圖片路徑,調用保存圖片到相冊的方法
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    // 通過url來截圖地址
    // 先將發(fā)送的請求里面的url轉換成字符串
    NSString *url = request.URL.absoluteString;
    // 找到標記所在的方法,確定截取范圍
    NSRange range = [url rangeOfString:@"dx://?src="];
    // 判斷獲得的range是否不為空,如果不為空,就不允許發(fā)送請求,并截圖范圍之后的字符串,那就是圖片的url
    if (range.length > 0) {
        // 先確定獲取范圍的長度,
        NSUInteger loc = range.location + range.length;
        // 根據這個長度,取范圍之后的字符串,就取得圖片的路徑了
        NSString *imgSrc = [url substringFromIndex:loc];
        // 根據路徑,將其保存到相冊
        [self saveImageToAlbum:imgSrc];
        
        return NO;
    }
  return YES;
}

效果圖:

效果圖:首頁
效果圖:webView頁面

上面的代碼,只是部分,而且還沒有做代碼的重構,只是實現了功能, 如有需要源碼,可以到我的GitHub首頁下載源碼,

如有不足之處,還望大家斧正!!! 360°感謝!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市派敷,隨后出現的幾起案子蛹批,更是在濱河造成了極大的恐慌,老刑警劉巖篮愉,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腐芍,死亡現場離奇詭異,居然都是意外死亡试躏,警方通過查閱死者的電腦和手機猪勇,發(fā)現死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冗酿,“玉大人埠对,你說我怎么就攤上這事〔锰妫” “怎么了项玛?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長弱判。 經常有香客問我襟沮,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任开伏,我火速辦了婚禮膀跌,結果婚禮上,老公的妹妹穿的比我還像新娘固灵。我一直安慰自己捅伤,他們只是感情好,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布巫玻。 她就那樣靜靜地躺著丛忆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仍秤。 梳的紋絲不亂的頭發(fā)上熄诡,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音诗力,去河邊找鬼凰浮。 笑死,一個胖子當著我的面吹牛苇本,可吹牛的內容都是我干的袜茧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼圈澈,長吁一口氣:“原來是場噩夢啊……” “哼惫周!你這毒婦竟也來了?” 一聲冷哼從身側響起康栈,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤递递,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啥么,有當地人在樹林里發(fā)現了一具尸體登舞,經...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年悬荣,在試婚紗的時候發(fā)現自己被綠了菠秒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡氯迂,死狀恐怖践叠,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情嚼蚀,我是刑警寧澤禁灼,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站轿曙,受9級特大地震影響弄捕,放射性物質發(fā)生泄漏僻孝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一守谓、第九天 我趴在偏房一處隱蔽的房頂上張望穿铆。 院中可真熱鬧,春花似錦斋荞、人聲如沸荞雏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讯檐。三九已至,卻和暖如春染服,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叨恨。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工柳刮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人痒钝。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓秉颗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親送矩。 傳聞我的和親對象是個殘疾皇子蚕甥,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內容