国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - IOS - iOS9中的WebKit 與 Safari帶來(lái)的驚喜

iOS9中的WebKit 與 Safari帶來(lái)的驚喜

2020-12-29 16:04iOS開發(fā)網(wǎng) IOS

這篇文章主要介紹了iOS9中的WebKit 與 Safari帶來(lái)的驚喜的相關(guān)資料,需要的朋友可以參考下

每個(gè)用過(guò) UIWebView 的iOS開發(fā)者對(duì)其諸多的限制和有限的功能也深有感觸。悻然,自iOS8推出 WebKit 框架后將改變這一窘境。在本文我將會(huì)深入WebKit來(lái)體驗(yàn)一下它給我們帶來(lái)的好處,同時(shí)也看看在iOS9中新加入的 SFSafariViewController 有些什么新的驚喜。

通用的瀏覽行為

所謂的通用瀏覽行為主要可以歸納為以下的幾種:

網(wǎng)頁(yè)載入進(jìn)度
前進(jìn)
后退
刷新

如果每個(gè)用到 WebView 的 app都要做一個(gè)專用的Controller也挺麻煩的,我以前就直接采用其它第三方寫好的包來(lái)完成。

但現(xiàn)在,如果用 WKWebView 將變得很方便,以代碼說(shuō)話吧:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class ViewController: UIViewController {
 
  var webView: WKWebView!
  @IBOutlet weak var progressView: UIProgressView!
    
  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)!
    
    // 實(shí)例化 WKWebView
    self.webView = WKWebView(frame: CGRectZero)
  }
  
 
  override func viewDidLoad() {
    super.viewDidLoad()
 
    // 編程式加入 WKWebView
    view.addSubview(webView)
    view.insertSubview(webView, aboveSubview: progressView)
    webView.translatesAutoresizingMaskIntoConstraints = false
    
    let widthConstraint = NSLayoutConstraint(item:webView, attribute: .Width, relatedBy: .Equal, toItem: view, attribute: .Width, multiplier: 1 , constant: 0)
    view.addConstraint(widthConstraint)
    
    let heightConstraint = NSLayoutConstraint(item:webView,attribute: .Height, relatedBy: .Equal,toItem: view, attribute: .Height, multiplier:1, constant: -46)
    
    view.addConstraint(heightConstraint)
    
    // 檢測(cè)webView對(duì)象屬性的變化
    webView.addObserver(self, forKeyPath: "loading", options: .New, context: nil)
    webView.addObserver(self, forKeyPath: "title", options: .New, context: nil)
    
    //加載網(wǎng)頁(yè)
 
    let request = NSURLRequest(URL: NSURL(string: "http://ray.dotnetage.com")!)
    
    webView.loadRequest(request)
    
  }
 
 
  override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
  
    if (keyPath == "loading") {
 
      // 檢測(cè)按鈕的可用性
      forwardButton.enabled = webView.canGoBack
      backButton.enabled = webView.canGoBack
      stopButton.image = webView.loading ? UIImage(name: "Cross") : UIImage(named: "Syncing")
 
    } else if keyPath == "title" {
 
      title = webView.title
 
    } else if keyPath == "estimatedProgress" {
 
      progressView.hidden = webView.estimatedProgress == 1
      progressView.setProgress(Float(webView.estimatedProgress), animated: true)
 
    }
  }
}

這些代碼我覺得沒什么好說(shuō)的,除了WKWebView不能通過(guò) IB 來(lái)可視化構(gòu)建外,以上的代碼最多是將 Autolayout 部分的代碼優(yōu)化一下就是了。寫一寫,做個(gè) Example 就懂了。

與 Javascript 通信

通過(guò)WebKit就不需要通過(guò) javascript 橋的方式來(lái)與DOM通信了。其實(shí)這也不是什么新技術(shù),早再 windows98 在VB或者在Delphi中也可以通過(guò)COM接口用完全相類似的手法與DOM通信了。

廢話不多說(shuō),講講 WebKit 的基本原理吧。以下是 WebKit Host 的Web進(jìn)程 與 App 主進(jìn)程的通信關(guān)系示意圖:

 

這里包含兩個(gè)過(guò)程

執(zhí)行 javascript 腳本

我們可以將 javascript 腳本包含于 App 的 Bundle 內(nèi),作為應(yīng)用程序資源。在運(yùn)行期將其通過(guò) WebKit 注入至目標(biāo)網(wǎng)頁(yè)內(nèi)執(zhí)行。

首先我們要準(zhǔn)備一個(gè)目標(biāo)網(wǎng)頁(yè),這里就以我自己的博客來(lái)做一個(gè)示例(http://ray.dotnetage.com )。在 App 中用WebKit打開是這樣的

iOS9中的WebKit 與 Safari帶來(lái)的驚喜

現(xiàn)在,我就將我博客上首頁(yè)的大標(biāo)題的文字改掉,具體的代碼很簡(jiǎn)單:

$(".page-header h1").text("iOS注入測(cè)試");

然后,在 iOS項(xiàng)目?jī)?nèi)增加一個(gè)叫 inject.js 的腳本文件,將上述代碼復(fù)制其內(nèi)。

在 App 內(nèi)包含的 javascript 腳本最好先在瀏覽器的控制臺(tái)內(nèi)執(zhí)行一次,以確保腳本自身是可以被正確執(zhí)行的。如果腳本中含有潛在錯(cuò)誤,在App內(nèi)是無(wú)法檢測(cè)得到的。

然后,在控制器的構(gòu)造函數(shù)內(nèi)創(chuàng)建一個(gè) WKWebViewConfiguration 實(shí)例,并作為參數(shù)傳入 WKWebView的構(gòu)造函數(shù),具體代碼如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// ViewController.swift
 
import WebKit
 
class ViewController : UIViewController {
 
    var webView: WKWebView!
 
    required init(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)!
      
 
      let configuation = WKWebViewConfiguration()
 
      configuation.userContentController.addUserScript(getUserScript("inject"))
      
      self.webView = WKWebView(frame: CGRectZero,configuration: configuation)
    }
 
  // 從資源中讀取 javascript 腳本
  func getUserScript(fromName: String)-> WKUserScript {
    let filePath = NSBundle.mainBundle().pathForResource(fromName, ofType: "js")
    let js = try! String(contentsOfFile: filePath!, encoding: NSUTF8StringEncoding)
    return WKUserScript(source: js, injectionTime: .AtDocumentEnd, forMainFrameOnly: true)
  }
    ...
}

此代碼段中需要注意的另一點(diǎn)是在自定義方法 getUserScript() 所返回的 WKUserScript 對(duì)象。我們可以通過(guò) injectionTime 決定將腳本注入至HTML的開始部分還是在文檔的尾部。

再次執(zhí)行代碼,效果如下:

iOS9中的WebKit 與 Safari帶來(lái)的驚喜

也就是說(shuō)我們可以在 app 內(nèi)通過(guò) WebKit 注入javascript后就可以任意地操控頁(yè)面內(nèi)的所有 DOM 對(duì)象!

javascript 的回調(diào)

除了從 app 一端將代碼注入到瀏覽器,執(zhí)行一個(gè)動(dòng)作。某些情況下我們還需要從網(wǎng)頁(yè)上做某一些處理后,例如將網(wǎng)頁(yè)內(nèi)的某些元素讀出并轉(zhuǎn)為一個(gè) json 對(duì)象集合,回傳給 App 處理。又或者我們的 app 在加載一個(gè)網(wǎng)頁(yè)之后想一次性地讀出頁(yè)面內(nèi)的所有圖像,當(dāng)用戶點(diǎn)擊這些圖像的時(shí)候我們用 app 的本地方式來(lái)全屏預(yù)覽,諸如此類。在這些語(yǔ)境下:

我們都得從網(wǎng)頁(yè)內(nèi)返回對(duì)象

也就是說(shuō),在網(wǎng)頁(yè)的進(jìn)程內(nèi)要向 app 進(jìn)程通信,那么我們就需要在腳本中使用:

webkit.messageHandlers.{MessageName}.postMessage([params]);

這個(gè)方法在標(biāo)準(zhǔn)的HTML5瀏覽器是不能直接執(zhí)行的,例如 Chrome和 Safair。只有通過(guò) WebKit Host 的頁(yè)面才會(huì)出現(xiàn)這個(gè) webkit 對(duì)象。 這并不難理解,只是 WebKit 在加載頁(yè)面后向 windows 注入了 webkit 這個(gè)實(shí)例,使得 javascript 可以通過(guò)它來(lái)向 app 發(fā)送信息。

如果我們要向 app 發(fā)送一個(gè)信息,例如:在頁(yè)面上的一個(gè)按鈕被點(diǎn)擊后,執(zhí)行 app 內(nèi)打開相冊(cè)的代碼,那么就得先在 javascript 上寫好這樣的代碼:

?
1
2
3
$("#mybutton").click(function(){
  webkit.messageHandlers.openPhotoLibrary.postMessage();
});

請(qǐng)留意 openPhotoLibrary 這個(gè)對(duì)象在Swift是沒有,當(dāng)這個(gè)方法被回傳到 Swift 的時(shí)候這只是一個(gè)消息的名字,而在Swift中要接收這種來(lái)至于瀏覽器發(fā)送的信息我們的控制器就需要實(shí)現(xiàn) WKScriptMessageHandler 這個(gè)接口,它只有一個(gè)方法,我們多花些篇幅直接將這個(gè)接口的代碼打開:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/*! A class conforming to the WKScriptMessageHandler protocol provides a
 method for receiving messages from JavaScript running in a webpage.
 */
public protocol WKScriptMessageHandler : NSObjectProtocol {
  
  /*! @abstract Invoked when a script message is received from a webpage.
   @param userContentController The user content controller invoking the
   delegate method.
   @param message The script message received.
   */
  @available(iOS 8.0, *)
  public func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage)
}

那么,我們就直接實(shí)現(xiàn)這個(gè)接口:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ViewController: UIViewController, WKScriptMessageHandler {
 
 
  required init(coder aDecoder: NSCoder) {
 
    // ... 之前的代碼同上
 
    configuation.userContentController.addScriptMessageHandler(self, name: "openPhotoLibrary")
 
    self.webView = WKWebView(frame: CGRectZero,configuration: configuation)
  }
 
  ...
 
 
  func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
    if message.name == "openPhotoLibrary" {
      // 這里就可以加入打開相冊(cè)的代碼了
    }
  }
}

從代碼就可以看出原理的一二:

在構(gòu)造 WKWebView 之前要用 addScriptMessageHandler 方法向配置對(duì)象注冊(cè)一個(gè)消息名,這里的例程是 "openPhotoLibrary"。
實(shí)現(xiàn) WKScriptMessageHandler 接口,從 userContentController() 方法的 message.name 參數(shù)中判斷消息的源頭,執(zhí)行對(duì)應(yīng)的代碼。

另外,如果我們需要從javascript腳本中向 app 傳入對(duì)象,可以直接在 postMessage() 方法內(nèi)將對(duì)象作為參數(shù)輸入,但通常這個(gè)參數(shù)的類型應(yīng)該是一個(gè)數(shù)組或者是普通的JSON對(duì)象,這樣在 app 才能用字典對(duì)象將其從新讀出。

例如,我從當(dāng)前網(wǎng)頁(yè)中將所有的菜單的地址和名稱讀出,并生成了一個(gè) menus 的 javascript 數(shù)組對(duì)象:

?
1
2
3
4
5
6
7
8
var menus = $(".navbar a").map(function(n,i){
  return {
    title: $(n).text,
    link: $(n).attr("href")
  };
});
 
webkit.messageHandlers.didFetchMenus.postMessage(menus);

這里就略過(guò)接口實(shí)現(xiàn),直接看 userContentController 方法實(shí)現(xiàn):

?
1
2
3
4
5
6
7
8
9
10
11
12
var menus: [Menus]?
 
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
  if message.name == "didFetchMenus" {
    if let resultArray = message.body as? [Dictionary<String,String>] {
      menus = resultArray.map{ Menu(dict: $0) }
 
      // 這里就取出并將JSON轉(zhuǎn)換為 Swift 的Menu對(duì)象了
      print(menus)
    }
  }
}

iOS9 中的 Safair 瀏覽器

在 iOS9 中加入了 SafariServices 這個(gè)新的模塊,其作用就是提供了一個(gè)全功能的內(nèi)嵌式 Safair,通過(guò)
SFSafariViewController 就能像普通的 控制器那樣使用。

以下是一個(gè)簡(jiǎn)單的例子

?
1
2
3
4
5
6
7
8
9
10
import UIKit
import SafariServices
 
class ViewController: UIViewController {
  @IBAction func openBrowser(sender: AnyObject) {
    let safari = SFSafariViewController(URL:NSURL(string:"http://www.apple.com")!)
      
    self.showViewController(safari, sender: self)
  }
}

SFSafariViewController 和 WebKit 的最大區(qū)別是 SFSafariViewController 沒有什么可控制方法,只是一個(gè)可以完全嵌入到 app 中的一個(gè)控制器,避免了像以前那樣如果打開一個(gè)外部鏈接要跳出當(dāng)前的app,而且 SFSafariViewController 嵌入的 Safari 和 Safari 內(nèi)的所有功能是一樣的,同樣支持 3D Touch 和切頁(yè)的等特色功能。且當(dāng)我們的 app 采用外部網(wǎng)絡(luò)帳號(hào)進(jìn)行集成登錄時(shí),Safari 能更直接獲取到當(dāng)前 app的應(yīng)用上下文,而無(wú)須再跳出重新在外部登入后再返回至App。這無(wú)疑是大大地增強(qiáng)了 app 在與 Safari 集成的時(shí)的使用體驗(yàn)。

在 Apple 的開發(fā)者網(wǎng)站上對(duì) WebKit 與 SafariServices 的選擇上給出了這樣的意見:

如果需要與網(wǎng)頁(yè)交互則選擇 WebKit
如果需要與Safari具有同樣的使用體驗(yàn)且不需要與網(wǎng)頁(yè)交互推薦使用 SafariServices

這確實(shí)是一項(xiàng)很不錯(cuò)的更新。

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 久久久久久久久久久久网站 | 亚洲激情在线播放 | а天堂中文最新一区二区三区 | 性网站在线观看 | 噜噜噜噜狠狠狠7777视频 | 日韩三级电影在线观看 | 精品在线 | 久国产精品韩国三级视频 | 美女超碰| 黄色免费在线观看网址 | 精品免费av | 国产一区二区三区视频在线观看 | 91在线日韩 | 国内精品久久久久久中文字幕 | 一区二区三区四区精品 | 国产午夜精品久久久久久久 | 久久久久国产 | 亚洲 欧美 精品 | 亚洲一级毛片 | 亚洲视频二区 | 午夜精 | 四虎欧美 | 91网站入口 | 免费在线看黄 | 亚洲精品乱码久久久久久金桔影视 | 日韩视频三区 | 亚洲毛片在线观看 | h片在线| 91麻豆蜜桃一区二区三区 | 中文字幕精品一区二区精品绿巨人 | 欧美性一区二区三区 | 亚洲久久 | 欧美日本韩国一区二区 | 亚洲成人精品一区 | 欧美 亚洲 另类 激情 另类 | 自拍第1页 | 亚洲综合视频在线 | 成人福利 | 亚洲成av在线| 久久久久一区二区 | 久久精品在线视频 |