激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - IOS - iOS9中的WebKit 與 Safari帶來的驚喜

iOS9中的WebKit 與 Safari帶來的驚喜

2020-12-29 16:04iOS開發網 IOS

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

每個用過 UIWebView 的iOS開發者對其諸多的限制和有限的功能也深有感觸。悻然,自iOS8推出 WebKit 框架后將改變這一窘境。在本文我將會深入WebKit來體驗一下它給我們帶來的好處,同時也看看在iOS9中新加入的 SFSafariViewController 有些什么新的驚喜。

通用的瀏覽行為

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

網頁載入進度
前進
后退
刷新

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

但現在,如果用 WKWebView 將變得很方便,以代碼說話吧:

?
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)!
    
    // 實例化 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)
    
    // 檢測webView對象屬性的變化
    webView.addObserver(self, forKeyPath: "loading", options: .New, context: nil)
    webView.addObserver(self, forKeyPath: "title", options: .New, context: nil)
    
    //加載網頁
 
    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") {
 
      // 檢測按鈕的可用性
      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)
 
    }
  }
}

這些代碼我覺得沒什么好說的,除了WKWebView不能通過 IB 來可視化構建外,以上的代碼最多是將 Autolayout 部分的代碼優化一下就是了。寫一寫,做個 Example 就懂了。

與 Javascript 通信

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

廢話不多說,講講 WebKit 的基本原理吧。以下是 WebKit Host 的Web進程 與 App 主進程的通信關系示意圖:

 

這里包含兩個過程

執行 javascript 腳本

我們可以將 javascript 腳本包含于 App 的 Bundle 內,作為應用程序資源。在運行期將其通過 WebKit 注入至目標網頁內執行。

首先我們要準備一個目標網頁,這里就以我自己的博客來做一個示例(http://ray.dotnetage.com )。在 App 中用WebKit打開是這樣的

iOS9中的WebKit 與 Safari帶來的驚喜

現在,我就將我博客上首頁的大標題的文字改掉,具體的代碼很簡單:

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

然后,在 iOS項目內增加一個叫 inject.js 的腳本文件,將上述代碼復制其內。

在 App 內包含的 javascript 腳本最好先在瀏覽器的控制臺內執行一次,以確保腳本自身是可以被正確執行的。如果腳本中含有潛在錯誤,在App內是無法檢測得到的。

然后,在控制器的構造函數內創建一個 WKWebViewConfiguration 實例,并作為參數傳入 WKWebView的構造函數,具體代碼如下:

 

?
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)
  }
    ...
}

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

再次執行代碼,效果如下:

iOS9中的WebKit 與 Safari帶來的驚喜

也就是說我們可以在 app 內通過 WebKit 注入javascript后就可以任意地操控頁面內的所有 DOM 對象!

javascript 的回調

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

我們都得從網頁內返回對象

也就是說,在網頁的進程內要向 app 進程通信,那么我們就需要在腳本中使用:

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

這個方法在標準的HTML5瀏覽器是不能直接執行的,例如 Chrome和 Safair。只有通過 WebKit Host 的頁面才會出現這個 webkit 對象。 這并不難理解,只是 WebKit 在加載頁面后向 windows 注入了 webkit 這個實例,使得 javascript 可以通過它來向 app 發送信息。

如果我們要向 app 發送一個信息,例如:在頁面上的一個按鈕被點擊后,執行 app 內打開相冊的代碼,那么就得先在 javascript 上寫好這樣的代碼:

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

請留意 openPhotoLibrary 這個對象在Swift是沒有,當這個方法被回傳到 Swift 的時候這只是一個消息的名字,而在Swift中要接收這種來至于瀏覽器發送的信息我們的控制器就需要實現 WKScriptMessageHandler 這個接口,它只有一個方法,我們多花些篇幅直接將這個接口的代碼打開:

?
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)
}

那么,我們就直接實現這個接口:

 

?
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" {
      // 這里就可以加入打開相冊的代碼了
    }
  }
}

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

在構造 WKWebView 之前要用 addScriptMessageHandler 方法向配置對象注冊一個消息名,這里的例程是 "openPhotoLibrary"。
實現 WKScriptMessageHandler 接口,從 userContentController() 方法的 message.name 參數中判斷消息的源頭,執行對應的代碼。

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

例如,我從當前網頁中將所有的菜單的地址和名稱讀出,并生成了一個 menus 的 javascript 數組對象:

?
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);

這里就略過接口實現,直接看 userContentController 方法實現:

?
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轉換為 Swift 的Menu對象了
      print(menus)
    }
  }
}

iOS9 中的 Safair 瀏覽器

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

以下是一個簡單的例子

?
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 的最大區別是 SFSafariViewController 沒有什么可控制方法,只是一個可以完全嵌入到 app 中的一個控制器,避免了像以前那樣如果打開一個外部鏈接要跳出當前的app,而且 SFSafariViewController 嵌入的 Safari 和 Safari 內的所有功能是一樣的,同樣支持 3D Touch 和切頁的等特色功能。且當我們的 app 采用外部網絡帳號進行集成登錄時,Safari 能更直接獲取到當前 app的應用上下文,而無須再跳出重新在外部登入后再返回至App。這無疑是大大地增強了 app 在與 Safari 集成的時的使用體驗。

在 Apple 的開發者網站上對 WebKit 與 SafariServices 的選擇上給出了這樣的意見:

如果需要與網頁交互則選擇 WebKit
如果需要與Safari具有同樣的使用體驗且不需要與網頁交互推薦使用 SafariServices

這確實是一項很不錯的更新。

延伸 · 閱讀

精彩推薦
  • IOSiOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    這篇文章主要介紹了iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果的相關資料,需要的朋友可以參考下...

    jiangamh8882021-01-11
  • IOSiOS中UILabel實現長按復制功能實例代碼

    iOS中UILabel實現長按復制功能實例代碼

    在iOS開發過程中,有時候會用到UILabel展示的內容,那么就設計到點擊UILabel復制它上面展示的內容的功能,也就是Label長按復制功能,下面這篇文章主要給大...

    devilx12792021-04-02
  • IOSiOS開發之視圖切換

    iOS開發之視圖切換

    在iOS開發中視圖的切換是很頻繁的,獨立的視圖應用在實際開發過程中并不常見,除非你的應用足夠簡單。在iOS開發中常用的視圖切換有三種,今天我們將...

    執著丶執念5272021-01-16
  • IOSiOS實現控制屏幕常亮不變暗的方法示例

    iOS實現控制屏幕常亮不變暗的方法示例

    最近在工作中遇到了要將iOS屏幕保持常亮的需求,所以下面這篇文章主要給大家介紹了關于利用iOS如何實現控制屏幕常亮不變暗的方法,文中給出了詳細的...

    隨風13332021-04-02
  • IOSiOS中MD5加密算法的介紹和使用

    iOS中MD5加密算法的介紹和使用

    MD5加密是最常用的加密方法之一,是從一段字符串中通過相應特征生成一段32位的數字字母混合碼。對輸入信息生成唯一的128位散列值(32個字符)。這篇文...

    LYSNote5432021-02-04
  • IOSiOS開發技巧之狀態欄字體顏色的設置方法

    iOS開發技巧之狀態欄字體顏色的設置方法

    有時候我們需要根據不同的背景修改狀態欄字體的顏色,下面這篇文章主要給大家介紹了關于iOS開發技巧之狀態欄字體顏色的設置方法,文中通過示例代碼...

    夢想家-mxj8922021-05-10
  • IOSiOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)

    iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和

    這篇文章主要介紹了iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)的相關資料,需要的朋友可以參考下...

    CodingFire13652021-02-26
  • IOS詳解iOS中多個網絡請求的同步問題總結

    詳解iOS中多個網絡請求的同步問題總結

    這篇文章主要介紹了詳解iOS中多個網絡請求的同步問題總結,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧...

    liang199111302021-03-15
主站蜘蛛池模板: 7777视频 | 看国产毛片 | xxx18hd18hd日本 | 国产精品亚洲一区二区三区久久 | 鸳鸯谱在线观看高清 | ,欧美特黄特色三级视频在线观看 | 亚洲最新无码中文字幕久久 | 亚洲成人夜色 | 精品无码久久久久久国产 | 九九热在线免费观看视频 | chinese乱子伦xxxx国语对白 | 国产盼盼私拍福利视频99 | 人成免费网站 | 日韩色视频在线观看 | 日本aaaa片毛片免费观蜜桃 | 成人在线免费小视频 | 97香蕉超级碰碰久久免费软件 | av在线观 | 欧美一级毛片免费观看视频 | 国产午夜亚洲精品理论片大丰影院 | 日本最新免费二区三区 | 性欧美视频在线观看 | 国产精品岛国久久久久久 | 久久久久久麻豆 | 综合网日日天干夜夜久久 | 成人在线高清视频 | 性欧美极品xxxx欧美一区二区 | 热99精品视频 | jizzyouxxxx| 欧美一级毛片大片免费播放 | 日韩剧情片 | 黄色片免费看网站 | 嗯~啊~弄嗯~啊h高潮视频 | 日韩av片在线免费观看 | 91av在线影院| 成人乱人乱一区二区三区 | 久久精品亚洲精品国产欧美kt∨ | 天天操天天插 | 成人黄色短视频在线观看 | 91 免费看片| 在线成人一区二区 |