最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2015年11月14日 16:41:48   投稿:hebedich  
這篇文章主要介紹了iOS9中的WebKit 與 Safari帶來(lái)的驚喜的相關(guān)資料,需要的朋友可以參考下

每個(gè)用過(guò) UIWebView 的iOS開(kāi)發(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è)專(zhuān)用的Controller也挺麻煩的,我以前就直接采用其它第三方寫(xiě)好的包來(lái)完成。

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

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)

    }
  }
}

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

與 Javascript 通信

通過(guò)WebKit就不需要通過(guò) javascript 橋的方式來(lái)與DOM通信了。其實(shí)這也不是什么新技術(shù),早再 windows98 在VB或者在Delphi中也可以通過(guò)COM接口用完全相類(lèi)似的手法與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打開(kā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ù),具體代碼如下:

// 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的開(kāi)始部分還是在文檔的尾部。

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

也就是說(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ù)覽,諸如此類(lèi)。在這些語(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)打開(kāi)相冊(cè)的代碼,那么就得先在 javascript 上寫(xiě)好這樣的代碼:

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

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

/*! 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è)接口:

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" {
      // 這里就可以加入打開(kāi)相冊(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ù)的類(lèi)型應(yīng)該是一個(gè)數(shù)組或者是普通的JSON對(duì)象,這樣在 app 才能用字典對(duì)象將其從新讀出。

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

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):

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)單的例子

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 沒(méi)有什么可控制方法,只是一個(gè)可以完全嵌入到 app 中的一個(gè)控制器,避免了像以前那樣如果打開(kāi)一個(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 的開(kāi)發(fā)者網(wǎng)站上對(duì) WebKit 與 SafariServices 的選擇上給出了這樣的意見(jiàn):

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

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

相關(guān)文章

  • 通過(guò)UIKit坐標(biāo)系來(lái)全面掌握iOS中的UIScrollView組件

    通過(guò)UIKit坐標(biāo)系來(lái)全面掌握iOS中的UIScrollView組件

    iOS開(kāi)發(fā)套件中的UIScrollView組件十分強(qiáng)大,不僅是滾動(dòng),縮放操作也能夠控制自如,其核心當(dāng)然是坐標(biāo)軸上的控制,下面就通過(guò)UIKit坐標(biāo)系來(lái)全面掌握iOS中的UIScrollView組件
    2016-05-05
  • 基于UIControl控件實(shí)現(xiàn)ios點(diǎn)贊功能

    基于UIControl控件實(shí)現(xiàn)ios點(diǎn)贊功能

    在開(kāi)發(fā)當(dāng)中,可能很多時(shí)候都需要做個(gè)點(diǎn)贊的需求,如果用按鈕實(shí)現(xiàn),按鈕作為一個(gè)系統(tǒng)復(fù)合控件,外部是一個(gè) View--》UIControl的容器,本文給大家分享一個(gè)基于UIControl控件實(shí)現(xiàn)ios點(diǎn)贊功能,需要的朋友可以參考下
    2015-09-09
  • iOS 二維碼掃描和應(yīng)用跳轉(zhuǎn)

    iOS 二維碼掃描和應(yīng)用跳轉(zhuǎn)

    本文講解如何使用原生框架實(shí)現(xiàn)二維碼掃描功能,并且進(jìn)行掃描后的項(xiàng)目跳轉(zhuǎn)。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-03-03
  • iOS獲取圖片區(qū)域主色的方法

    iOS獲取圖片區(qū)域主色的方法

    這篇文章主要為大家詳細(xì)介紹了iOS獲取圖片區(qū)域主色的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 解決ios手機(jī)中input輸入框光標(biāo)過(guò)長(zhǎng)的問(wèn)題

    解決ios手機(jī)中input輸入框光標(biāo)過(guò)長(zhǎng)的問(wèn)題

    在項(xiàng)目中做移動(dòng)端頁(yè)面,發(fā)現(xiàn)IOS 的光標(biāo)大小很大,和安卓的完全不一樣,怎么來(lái)調(diào)整大小呢?下面小編給大家?guī)?lái)了ios手機(jī)中input輸入框光標(biāo)過(guò)長(zhǎng)問(wèn)題的解決方法,一起看看吧
    2018-08-08
  • 設(shè)計(jì)模式中的迭代器模式在Cocoa Touch框架中的使用

    設(shè)計(jì)模式中的迭代器模式在Cocoa Touch框架中的使用

    這篇文章主要介紹了設(shè)計(jì)模式中的迭代器模式在Cocoa Touch框架中的使用,示例代碼為傳統(tǒng)的Objective-C,需要的朋友可以參考下
    2016-03-03
  • 針對(duì)iOS開(kāi)發(fā)的一些Xcode使用技巧小結(jié)

    針對(duì)iOS開(kāi)發(fā)的一些Xcode使用技巧小結(jié)

    這篇文章主要介紹了針對(duì)iOS開(kāi)發(fā)的一些Xcode使用技巧小結(jié),Xcode是Mac上編寫(xiě)iOS應(yīng)用的開(kāi)發(fā)環(huán)境,需要的朋友可以參考下
    2015-12-12
  • iOS支付寶使用方法詳解

    iOS支付寶使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了iOS支付寶的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • iOS中設(shè)置圓角的幾種方法示例

    iOS中設(shè)置圓角的幾種方法示例

    這篇文章主要介紹了iOS中設(shè)置圓角的三種方法,其中包括使用layer屬性、使用繪圖設(shè)置圓角以及通過(guò)另一張mask圖創(chuàng)建新圖,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-03-03
  • 輕松搞定iOS遠(yuǎn)程消息推送

    輕松搞定iOS遠(yuǎn)程消息推送

    這篇文章主要幫助大家輕松搞定iOS遠(yuǎn)程消息推送,討論遠(yuǎn)程推送的流程與配置過(guò)程,感興趣的小伙伴們可以參考一下
    2016-09-09

最新評(píng)論

西吉县| 海原县| 上思县| 阿拉善盟| 马山县| 烟台市| 樟树市| 泸州市| 北海市| 太仓市| 东乡族自治县| 伊吾县| 祥云县| 会昌县| 乌鲁木齐县| 磴口县| 莱州市| 甘孜县| 阿拉善右旗| 榆林市| 岳普湖县| 宁德市| 武夷山市| 道孚县| 册亨县| 淮滨县| 舞阳县| 吉水县| 厦门市| 涞源县| 治多县| 云梦县| 高邮市| 元江| 金川县| 浦城县| 祁连县| 望城县| 依安县| 瓮安县| 石林|