iOS WKWebView使用總結

iOS WKWebView與JS交互


WKWebView

iOS8.0之后我們使用 WebKit框架中的WKWebView來加載網頁。

WKWebViewConfiguration來配置JS交互。

其中的和JS交互的功能

  • WKPreferences(是WKWebViewConfiguration的屬性) 中的javaScriptEnabled是Bool實行來打開或者關閉javaScript
    *javaScriptCanOpenWindowsAutomaticallyBool控制javaScript打開windows
`WKWebView`中的`navigationDelegate`協議可以監聽加載網頁的周期和結果。

* 判斷鏈接是否允許跳轉

    ```
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction     decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
    ```

* 拿到響應后決定是否允許跳轉

    ```
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
    ```

* 鏈接開始加載時調用

    ```
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
    ```

* 收到服務器重定向時調用

    ```
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
    ```

* 加載錯誤時調用

    ```
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
    ```

* 當內容開始到達主幀時被調用(即將完成)

    ```
    - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
    ```

* 加載完成

    ```
    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;
    ```

* 在提交的主幀中發生錯誤時調用

    ```
    - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
    ```


* 當webView需要響應身份驗證時調用(如需驗證服務器證書)

    ```
    - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge    completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable   credential))completionHandler;
    ```

* 當webView的web內容進程被終止時調用。(iOS 9.0之后)

    ```
    - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));
    ```
  • WKWebView中的WKUIDelegate實現UI彈出框的一些處理(警告面板、確認面板、輸入框)。
* 在JS端調用alert函數時,會觸發此代理方法。JS端調用alert時所傳的數據可以通過message拿到。在原生得到結果后,需要回調JS,是通過completionHandler回調。

    ```
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler 
    {
        NSLog(@"message = %@",message);
    }
    ```

* JS端調用confirm函數時,會觸發此方法,通過message可以拿到JS端所傳的數據,在iOS端顯示原生alert得到YES/NO后,通過completionHandler回調給JS端
 
    ```
    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler 
    {
        NSLog(@"message = %@",message);
    }
    ```

* JS端調用prompt函數時,會觸發此方法,要求輸入一段文本,在原生輸入得到文本內容后,通過completionHandler回調給JS
 
    ```
    - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler 
    { 
        NSLog(@"%s", __FUNCTION__);
        NSLog(@"%@", prompt); 
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS調用輸入框" preferredStyle:UIAlertControllerStyleAlert]; 
        [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) 
        { 
            textField.textColor = [UIColor redColor];
        }]; 
        [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) 
        { 
            completionHandler([[alert.textFields lastObject] text]); 
        }]]; 
            [self presentViewController:alert animated:YES completion:NULL]; 
    }
    ```

JS交互實現流程

使用WKWebView,JS調iOS-JS端必須使用window.webkit.messageHandlers.JS_Function_Name.postMessage(null),其中JS_Function_Name是iOS端提供個JS交互的Name。

例:

function iOSCallJsAlert() 
{
     alert('彈個窗,再調用iOS端的JS_Function_Name');
     window.webkit.messageHandlers.JS_Function_Name.postMessage({body: 'paramters'});
}

在注入JS交互Handler之后會用到[userContentController addScriptMessageHandler:self name:JS_Function_Name]。釋放使用到[userContentController removeScriptMessageHandlerForName:JS_Function_Name]

我們JS呼叫iOS通過上面的Handler在iOS本地會有方法獲取到。獲取到之后我們可以根據iOS和JS之間定義好的協議,來做出相應的操作。

 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 
{
    NSLog(@"JS調iOS  name : %@    body : %@",message.name,message.body);
}   

處理簡單的操作,可以讓JS打開新的web頁面,在WKWebViewWKNavigationDelegate協議中,判斷要打開的新的web頁面是否是含有你需要的東西,如果有需要就截獲,不打開并且進行本地操作。

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSString * url = navigationAction.request.URL.absoluteString;
    if ([url hasPrefix:@"alipays://"] || [url hasPrefix:@"alipay://"])
        {
            
            if ([[UIApplication sharedApplication] canOpenURL:navigationAction.request.URL])
            {
                [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
                if(decisionHandler)
                {
                    decisionHandler(WKNavigationActionPolicyCancel);
                }
            }
        }
}

iOS端調用JS中的函數只需要知道在JS中的函數名稱和函數需要傳遞的參數。通過原生的方法呼叫JS,
iOSCallJsAlert()是JS端的函數名稱,如果有參數iOS端寫法iOSCallJsAlert('p1','p2')

[webView evaluateJavaScript:@"iOSCallJsAlert()" completionHandler:nil]

JS和iOS注意的地方

①. 上面提到[userContentController addScriptMessageHandler:self name:JS_Function_Name]是注冊JS的MessageHandler,但是WKWebView在多次調用loadRequest,會出現JS無法調用iOS端。我們需要在loadRequest和reloadWebView的時候需要重新注入。(在注入之前需要移除再注入,避免造成內存泄漏)

如果message.body中沒有參數,JS代碼中需要傳null防止iOS端不會接收到JS的交互。

window.webkit.messageHandlers.kJS_Login.postMessage(null)

②. 在WKWebView中點擊沒有反應的時候,可以參考一下處理

 -(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures 
 {
       if (!navigationAction.targetFrame.isMainFrame) 
       {
           [webView loadRequest:navigationAction.request];
       }
       return nil;
 }

③. HTML中不能通過<a href="tel:123456789">撥號</a>來撥打iOS的電話。需要在iOS端的WKNavigationDelegate中截取電話在使用原生進行調用撥打電話。其中的[navigationAction.request.URL.scheme isEqualToString:@"tel"]中的@"tel"是JS中的定義好,并iOS端需要知道的。發送請求前決定是否跳轉,并在此攔截撥打電話的URL

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
     /// <a href="tel:123456789">撥號</a>
     if ([navigationAction.request.URL.scheme isEqualToString:@"tel"]) 
     {
          decisionHandler(WKNavigationActionPolicyCancel);
          NSString * mutStr = [NSString stringWithFormat:@"telprompt://%@",navigationAction.request.URL.resourceSpecifier];
          if ([[UIApplication sharedApplication] canOpenURL:mutStr.URL]) 
          {
              if (iOS10()) 
              {
                  [[UIApplication sharedApplication] openURL:mutStr.URL options:@{} completionHandler:^(BOOL success) {}];
              } 
              else 
              {
                  [[UIApplication sharedApplication] openURL:mutStr.URL];
              }
          }
       } 
       else 
       {
           decisionHandler(WKNavigationActionPolicyAllow);
       }
}

④. 在執行goBackreloadgoToBackForwardListItem之后請不要馬上執行loadRequest,使用延遲加載。

⑤在使用中JS端:H5、DOM綁定事件。每一次JS方法調用iOS方法的時候,我都為這個JS方法綁定一個對應的callBack方法,這樣的話,同時在發送的消息中告訴iOS需要回調,iOS方法就可以執行完相關的方法后,直接回調相應的callBack方法,并攜帶相關的參數,這樣就可以完美的進行交互了。這是為了在JS調用iOS的時候,在- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message獲取到信息后,iOS端調用[_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {}];給JS發送消息,保證JS在獲取相關返回值時,一定能拿到值。

⑥根據需求清楚緩存和Cookie。

JS端可以參考:漫談js自定義事件、DOM/偽DOM自定義事件


WKWebview加載遠程JS文件和本地JS文件

在頁面請求成功 頁面加載完成之后調用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
completionHandlerJS是可以再收到調用之后給webView回調。

WKWebView遠程網頁加載遠程JS文件
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    [self.webView evaluateJavaScript:@"var script = document.createElement('script');"
     "script.type = 'text/javascript';"
     "script.src = 'http://www.ohmephoto.com/test.js';"
     "document.getElementsByTagName('head')[0].appendChild(script);"
                   completionHandler:^(id _Nullable object, NSError * _Nullable error)
     {
         NSLog(@"------error = %@ object = %@",error,object);
     }];
    
}

WKWebView遠程網頁加載本地JS

xcode新建找到Other->Empty,確定文件名XXX.js

一般需要在本地加載的JS都會很小,用原生JS直接加載就可以了

題外:看到網友是自定義NSURLProtocol類 - 高端大氣上檔次,請自行查閱。

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    NSString * plistPath = [[NSBundle mainBundle] pathForResource:@"XXX" ofType:@"js"];
    NSString * data = [NSString stringWithContentsOfFile:plistPath encoding:NSUTF8StringEncoding error:nil];//  [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
    
    [self.webView evaluateJavaScript:[NSString stringWithFormat:@"javascript:%@",data]
                   completionHandler:^(id _Nullable object, NSError * _Nullable error)
     {
         
     }];
}

第三方庫WebViewJavascriptBridge

GitHub地址WebViewJavascriptBridge
不做過多解釋,很好用的第三方庫。安卓也有相應的庫。同樣很強大。


WKWebView進度條

聲明屬性

@property (nonatomic, strong) UIProgressView *progressView;

//進度條初始化

- (UIProgressView *)progressView
{
    if (!_progressView)
    {
        
        _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 2)];
        _progressView.backgroundColor = [UIColor blueColor];
        _progressView.transform = CGAffineTransformMakeScale(1.0f, 1.5f);
        _progressView.progressTintColor = [UIColor app_color_yellow_eab201];
        [self.view addSubview:self.progressView];
    }
    return _progressView;
}

ViewController中添加Observer

[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];

dealloc找那個刪除Observer

[self.webView removeObserver:self forKeyPath:@"estimatedProgress"];

  • observeValueForKeyPath中添加對progressView的進度顯示操作
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
   if ([keyPath isEqualToString:@"estimatedProgress"])
   {
       self.progressView.progress = self.webView.estimatedProgress;
       if (self.progressView.progress == 1)
       {
           WeakSelfDeclare
           [UIView animateWithDuration:0.25f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^
           {
               weakSelf.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.4f);
           }
                            completion:^(BOOL finished)
           {
               weakSelf.progressView.hidden = YES;
           }];
       }
   }
}
  • 顯示progressView
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
{
       self.progressView.hidden = NO;
       self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.5f);
       [self.view bringSubviewToFront:self.progressView];
}
  • 隱藏progressView
   - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
   {
       self.progressView.hidden = YES;
  }
   - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
   {
       if(error.code==NSURLErrorCancelled)
       {
           [self webView:webView didFinishNavigation:navigation];
       }
       else
       {
           self.progressView.hidden = YES;
       }
   }
   - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
   {
       self.progressView.hidden = YES;
       [self.navigationItem setTitleWithCustomLabel:@"加載失敗"];
   }

WKWebView清楚緩存

有人是這么寫的

- (void)clearCache
{
    /* 取得Library文件夾的位置*/
    NSString *libraryDir = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask, YES)[0];
    /* 取得bundle id,用作文件拼接用*/ NSString *bundleId = [[[NSBundle mainBundle] infoDictionary]objectForKey:@"CFBundleIdentifier"];
    /* * 拼接緩存地址,具體目錄為App/Library/Caches/你的APPBundleID/fsCachedData */
    NSString *webKitFolderInCachesfs = [NSString stringWithFormat:@"%@/Caches/%@/fsCachedData",libraryDir,bundleId];
    NSError *error;
    /* 取得目錄下所有的文件,取得文件數組*/
    NSFileManager *fileManager = [NSFileManager defaultManager];
    //NSArray *fileList = [[NSArray alloc] init];
    //fileList便是包含有該文件夾下所有文件的文件名及文件夾名的數組
    NSArray *fileList = [fileManager contentsOfDirectoryAtPath:webKitFolderInCachesfs error:&error];
    /* 遍歷文件組成的數組*/
    for(NSString * fileName in fileList)
    {
        /* 定位每個文件的位置*/
        NSString * path = [[NSBundle bundleWithPath:webKitFolderInCachesfs] pathForResource:fileName ofType:@""];
        /* 將文件轉換為NSData類型的數據*/
        NSData * fileData = [NSData dataWithContentsOfFile:path];
        /* 如果FileData的長度大于2,說明FileData不為空*/
        if(fileData.length >2)
        {
            /* 創建兩個用于顯示文件類型的變量*/
            int char1 =0;
            int char2 =0;
            [fileData getBytes:&char1 range:NSMakeRange(0,1)];
            [fileData getBytes:&char2 range:NSMakeRange(1,1)];
            /* 拼接兩個變量*/ NSString *numStr = [NSString stringWithFormat:@"%i%i",char1,char2];
            /* 如果該文件前四個字符是6033,說明是Html文件,刪除掉本地的緩存*/
            if([numStr isEqualToString:@"6033"])
            {
                [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@",webKitFolderInCachesfs,fileName]error:&error]; continue;
                
            }
        }
    }
}

也可以這樣寫

- (void)cleanCacheAndCookie
{
    //清除cookies
    NSHTTPCookie *cookie;
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (cookie in [storage cookies])
    {
        [storage deleteCookie:cookie];
    }
    
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    NSURLCache * cache = [NSURLCache sharedURLCache];
    [cache removeAllCachedResponses];
    [cache setDiskCapacity:0];
    [cache setMemoryCapacity:0];
    
    WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore];
    [dateStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes]
                     completionHandler:^(NSArray<WKWebsiteDataRecord *> * __nonnull records)
     {
         for (WKWebsiteDataRecord *record  in records)
         {
             
             [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes
                                                       forDataRecords:@[record]
                                                    completionHandler:^
              {
                  NSLog(@"Cookies for %@ deleted successfully",record.displayName);
              }];
         }
     }];
}
- (void)dealloc
{
    [_webView stopLoading];
    [_webView setNavigationDelegate:nil];
    [self clearCache];
    [self cleanCacheAndCookie];
}

WKWebView修改userAgent

在項目中我們游戲直接使用以下方式寫入userAgent,出現了URL可以加載,但是URL里面的資源無法加載問題。但是在微信和外部Safari是可以的。后來查出,不要去直接整個修改掉userAgent。要在原有的userAgent加上你需要的userAgent字符串,進行重新注冊就可以了。(具體原因可能是外部游戲引擎,會默認取系統的userAgent來做他們的處理,你改掉整個會出現問題)。

[[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent":@"CustomUserAgent"}];
[[NSUserDefaults standardUserDefaults] synchronize];
[self.webView setCustomUserAgent:newUserAgent];

使用下面的修改userAgent
使用NSUserDefaults修改本地的userAgent
使用WKWebViewsetCustomUserAgent修改網絡userAgent

[self.webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error)
{
     NSString * userAgent = result;
     NSString * newUserAgent = [userAgent stringByAppendingString:@"CustomUserAgent"];
     [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent":newUserAgent}];
     [[NSUserDefaults standardUserDefaults] synchronize];
     [self.webView setCustomUserAgent:newUserAgent];
}];

WKWebView重定向問題

在使用過程中,我們獲取到一個鏈接需要webView打開,但是這個鏈接是可以直接重定向到別的地方的。
比如要直接打開AppStore,到相應的App下載頁面,不是打開webView
當我們需要打開的之前,我們用NSURLConnection來判斷是否有重定向。
代碼如下:

- (void)requestByURLConnectionString:(NSString *)string
{
    NSURL *url = [NSURL URLWithString:string];
    NSMutableURLRequest *quest = [NSMutableURLRequest requestWithURL:url];
    quest.HTTPMethod = @"GET";
    NSURLConnection *connect = [NSURLConnection connectionWithRequest:quest delegate:self];
    [connect start];
}

#pragma mark - NSURLConnectionDataDelegate
- (nullable NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(nullable NSURLResponse *)response
{
    NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *)response;
    
    NSLog(@"statusCode: %ld", urlResponse.statusCode);
    
    NSDictionary *headers = urlResponse.allHeaderFields;
    NSLog(@"%@", headers);
    NSLog(@"redirect   url: %@", headers[@"Location"]);    // 重定向的地址
    NSLog(@"newRequest url: %@", [request URL]);           // 重定向的地址或原地址
    NSLog(@"redirect response url: %@", [urlResponse URL]);// 觸發重定向請求的地址,
    if ([request URL] != nil && headers[@"Location"] != nil)
    {
       有重定向進行處理
    }
    else
    {
       無重定向處理
    }
    return request;
}

WKWebView時間顯示Nan問題 (js時間處理)

1 正常的處理如下:

1.  var regTime = result.RegTime;  
2.  var dRegTime = new Date(regTime);  
3.  var regHtml = dRegTime.getFullYear() + "年" + dRegTime.getMonth() + "月";

在iOS系統下,JS需要正則把-替換成/

var regTime = result.RegTime.replace(/\-/g, "/"); 

總結

iOS中的WKWebView使用簡單方便。使用它你只用將你用到的進行封裝。在你的ViewController中進行初始化WKWebView并加載和對其配置,就能完整的使用了。

iOS端和JS互相調用,有簡單的函數方法進行互相配合。在交互的時候需要雙方約定好特定的事件名稱。比如登錄、打開支付、彈出分享等常規操作。

JSiOS端發送消息使用window.webkit.messageHandlers.JS_Function_Name.postMessage(null)

iOS端接受JS發來的消息需要WKUserContentController添加Handler并且處理協議,在協議中判斷并處理JS端需要iOS端做的事件。

iOS調用JS直接使用WKWebView[webView evaluateJavaScript:@"JS函數名稱('參數1','參數2')" completionHandler:nil]來向JS發送消息。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • 前言 關于UIWebView的介紹,相信看過上文的小伙伴們,已經大概清楚了吧,如果有問題,歡迎提問。 本文是本系列...
    CoderLF閱讀 9,010評論 2 12
  • 前言: web頁面和app的直接的交互是很常見的東西,在ios8之前,用的是uiwebview,但是在ios8之后...
    qingchen91閱讀 2,964評論 6 25
  • 雖然WKWebView是在Apple的WWDC 2014隨iOS 8和OS X 10.10出來的,是為了解決UIW...
    winann閱讀 136,079評論 195 641
  • 沒上大學之前,我以為我真的吃膩了家鄉的菜肴,我以為我不會想念。直到上大學后,我從西南邊陲的一座小城來到了華北地區的...
    檸檬茶啊閱讀 438評論 2 3
  • 人總是心變得骯臟, 沾滿塵埃, 世界才變得丑惡不堪。
    月落傾閱讀 231評論 0 1