你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 遠程通知推送教程

遠程通知推送教程

編輯:IOS開發基礎

push_feature-250x250.png

本文翻譯自:raywenderlich.com,原文作者:Jack Wu,譯者:JMStack

iOS開發者們喜歡想象他的用戶們會每時每刻使用他們所開發的APP,但是殘酷的事實是他們的用戶會有關閉APP來處理其它事情的時候。就像你洗好的衣服總要人去疊吧。

幸好,推送通知功能可以讓開發者與用戶建立連接並進行簡單的交互,即使用戶當前並沒有使用APP!

從推送通知功能第一次問世到現在已經變得越來越強大。在iOS 9上,遠程推送可以做到:

  • 顯示短文本

  • 播放通知提示音

  • 設置APP圖標的角標

  • 在不打開APP的情況下,允許用戶與APP交互

  • 允許APP在後台靜默喚醒來執行任務

這份遠程推送通知教程會告訴你遠程推送的工作原理的並讓你了解它的一些特性。

在開始推送測試之前你需要具備以下條件:

  • 一台iOS設備。遠程推送不能在摸擬器上運行,所以你需要一台真機。

  • 一個開發者帳號。從Xcode7開始,在真機上測試APP不再需要加入開發者計劃。但是為了配置遠程推送,你需要有一個與APP ID對應的推送證書,獲得這個證書你需要加開發者計劃。

開始

為了接收發送遠程推送通知你必須完成以下3個主要的任務:

1、App必須正確配置並注冊APNS(Apple Push Notification Service),以便所有設置都完成時就能馬上接收到通知。

2、服務端必須向APNS發送一條明確指向一個或多個設備的通知。

3、App必需接收服務端發送的通知,App可以執行通知包含的任務或者在application的代理(delegate)回調方法內處理用戶交互行為。

任務1和任務3是這份推送通知教程主要關注的內容,因為這兩個任務是iOS開發者的工作。

任務2也會在這份教程中簡略的提及,並且多數情況僅僅是為了測試目的。發送一個遠程通知是App服務端的工作,並且這部分內部會因為App的不同而不同。大多數App都會使用第三方服務(比如Parse。com或者Google ColoudMessaging)推送通知,其它的App或使用定制化的解決方案或使用比較流行的框架(比如: Houston)。

正式開始之,下載已經准備好的WenderCast開始工程。WenderCast是一個讓用戶獲取raywenderlich.com播客節目和時實消息的應用。

在Xcode中打開WenderCast.xcodeproj簡單浏覽一下。編繹運行即可查看當前最新播客節目:

BuildAndRun1.jpg

這個App的存在的問題是當有新的播客節目可以獲取時不能通知到用戶。並且也不能顯示任何最新的消息。接下來你將用遠程推送功能修復這個問題!

為App配置遠程推送功能

推送通知需要較高的安全性。這點是非常重要的,因為你不會想讓其它人給你的用戶發送通知。這也就意味著要實現遠程推送功能你必需跳過一些坑。

打開遠程推送服務

第一步是更改App ID。在Xcode中進入 App Settings -> General 把 Bundle Identifier 改為任意唯一的字符串。

ChangeBundleID.png

接下來你需要在你的開發者帳號下添加打開了推送通知功能的App ID。幸運的是,Xcode有更簡單的方法實現這個步驟。進入 App Settings -> Capabilities 把Push Notifications設置為 On。

在Xcode完成一些下載後,看起應該會是下面的樣子

PushNotificaitonCapability.png

這個步驟背後的操作是,如果你當前的開發者帳號下沒有對應的App ID就會主動創建App ID,並且打開推送通知功能。你可以登陸開發者中心確認是否打開了這個功能:

MemberCenter1.jpg

如果這個過程中出現問題,可以手動創建App ID或者點擊開發者中心 + 或 Edit 按鈕開啟推送通知功能。

以上就是你目前需要的配置。

注冊遠程推送

注冊遠程推送需要兩步。第一步,你必需向用戶請求推送通知許可,獲得許可之後才能注冊遠程推送。如果所有步驟進行順利,系統將會向你提供一個 device token,你可以把它認為是當前設備的”地址”。

在WenderCast應用中你需要用在應用啟動後立即注冊遠程推送。

打開AppDelegate.swift,添加以下代碼到AppDelegate末尾。

func registerForPushNotifications(application: UIApplication) {
  let notificationSettings = UIUserNotificationSettings(
    forTypes: [.Badge, .Sound, .Alert], categories: nil)
  application.registerUserNotificationSettings(notificationSettings)
}

這個方法創建了一個 UIUserNotificationSettings 實例對象並把它作為參數傳給 registerUserNotificationSettings(_:) 。

UIUserNotificationSettings 存儲你的應用將到用到的通知類型設置。對於UIUserNotificationType的值你可以用下面幾個枚舉值的任意組合。

  • .Badge 允許App在圖標上顯示角標數字

  • .Sound 允許App播放聲音

  • .Alert 允許App顯示文本

UIUserNotificationCategory 是Set類型參數當前暫時傳 nil,以允許你指定你的App能夠處理的不同類型的通知。當你需要實現可交互的通知時,這樣的設置是必需的。後面的部分你將會用到可交互通知。

在 application(_:didFinishLaunchingWithOptions:launchOptions:): 方法內的第一行調用 registerForPushNotifications(_:) :

func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions:[NSObject: AnyObject]?) -> Bool {
  registerForPushNotifications(application)
  //...
}

編繹運行,當App啟動時你會收到一個彈窗請求通知許可:

BuildAndRun2.jpg

點擊 OK,現在App可以顯示通知了。但是,如果用戶拒絕了發送通知的請求該應怎麼辦?

當用戶接受或拒絕請求許可又或者之前做出過是否允許的選擇, UIApplicationDelegate 的一個代理方法將會被調用. 添加以下代碼到 AppDelegate:

func application(application: UIApplication,didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
}

在這個方法中,你會接收到另一個 UIUserNotificationSettings 實現對象。這個實例對象與之前你之前所傳入的不同。你之前傳入的是你所希望的設置,而當前這個是用戶當前授權的設置。

在App每次啟動時都調用 registerUserNotificationSettings(_:) 是相當重要的。因為用戶在任何時候都有可能在設置應用內改變通知的授權許可。 application(_:didRegisterUserNotificationSettings:) 方法會告訴你用戶當前給你的App什麼樣的授權許可。

現在第一步已經完成,你可以注冊遠程推送通知了。這一步相當簡單,因為你不再需要向用戶請求什麼許可了。用下面的代碼更新 application(_:didRegisterUserNotificationSettings:) 方法:

func application(application: UIApplication,didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
  if notificationSettings.types != .None {
    application.registerForRemoteNotifications()
  }
}

在上面的方法中,首先檢查當前用戶是否允許通知,如果允許直接調用 registerForRemoteNotifications()。

其次,registerForRemoteNotifications()的請求注冊的返回狀態會通過 UIApplicationDelegate協議中的某些方法通知你。

添加以下代碼到 AppDelegate :

1463994202124520.png

就像方法名所暗示的那樣,當注冊通知成功後系統會調用 application(_:didRegisterForRemoteNotificationsWithDeviceToken:) 方法,否則將會調用 application(_:didFailToRegisterForRemoteNotificationsWithError:)方法。

當前 application(_:didRegisterForRemoteNotificationsWithDeviceToken:) 方法的實現看起來難以理解,其實它僅僅只是獲取 deviceToken 然後轉換成字符串。deviceToken的值就是這個過程得到的結果。它是由APNs服務器提供用來標識當前設備當前App。當發送時推送通知的時候,App用deviceToken作為“地址”傳遞到當前設備。

注意:會有很多原因導致注冊失敗。最常碰到原因是程序運行在模擬器上,或者App ID設置不正確。具體原因打印error值會提供更加詳細的信息。

到此,編繹運行。確保你當前運行在真機上,你將會在控制台看到打印出的device token。下面將會是你看到的結果:

DeviceToken.png

把device token復制到某處保存。

在正式發送通知之前你還需要一點點配置,所以回到開發者中心。

創建一個SSL證書和PEM文件

在開發者中心進入 Certificates, Identifiers & Profiles -> Identifiers -> App IDs 找到你應用的App ID.在 Application Services 下面 Push Notifications 應該為 Configurable :

ConfigurablePushNotifications.png

點擊 Edit 滾動到 Push Notifications:

1463989449361471.png

在 Development SSL Certificate 欄下,點擊 Create Certificate… 接下來的步驟就是創建 CSR 文件。創建好CSR文件後點擊 continue 和 Generate,這步會用你創建的CSR文件生成證書。最後下載並運行生成好的證書,證書將被添加到你的鑰匙串應用中,並與私鑰成對。

1463989539559130.png

在開發者中心,你的App ID現在推送通知功能在development下應該處於Enable狀態。

PushNotificationEnabled.png

在關閉鑰匙串應用前還有最後一件事,右擊你剛才添加的證書,選擇 Export :

1463989597273139.png

保存在桌面並命名為WenderCastPush.p12。

SaveP12.png

你會被提示要求為你的.p12文件設置密碼,你可以選擇不輸或者輸入一個你想設置的密碼。這裡我用”WenderCastPush”作為密碼。接下來你需要輸入電腦登陸密碼來允許導出p12文件。

接下來,打開你的終端並執行以下命令來從p12文件生成PEM文件:

$ cd ~/Desktop
$ openssl pkcs12 -in WenderCastPush.p12 -out WenderCastPush.pem -nodes -clcerts

如果你導出p12文件時輸入了密碼,在這裡你必須輸入相同的密碼。

到此為止,你已經艱難的躍過了很多坑,這一切都是值得的。接下來你將用你生成的WenderCastPush.pem文件發送第一個通知。

發送通知

之前下載的開始工程會包含一個WenderCastPush文件;裡面包含兩個用於發送通知簡單腳本。你需要用到的是newspush.php。正如文件名所暗示的,這個腳本將會向你的用戶發送一個彈窗通知消息。

發送推送通知需要和APNS建立SSL連接,SSL連接是用之前創建的證書進行加密。這就是為什麼要生成 WenderCastPush.pem 文件。重命名 WenderCastPush.pem 為 ck.pem,並且替換掉當前已經存在於 WenderCastPush 文件夾下的 ck.pem 文件。

打開 newspush.php 並更新之前接收到的 $deviceToken 和導出文件時輸入的密碼 $passphrase

// Put your device token here (without spaces):
$deviceToken = '43e798c31a282d129a34d84472bbdd7632562ff0732b58a85a27c5d9fdf59b69';
// Put your private key's passphrase here:
$passphrase = 'WenderCastPush';

打開終端,cd 到 newspush.php 所在的文件夾,輸入:

ush.php 'Breaking News' 'https://raywenderlich.com'

如果進行順利,你的終端將會顯示:

Connected to APNS
Message successfully delivered

現在,你應該會收到你的第一條通知:

FirstPush-281x500.jpg

注意:如果你的App被打開並處於前台運行狀態,你將看不到任何東西。通知已經被投送但是App還不會處理這個通知。你只需要簡單的關閉App並重新發送通知即可。

常見問題

也許你會遇到以下問題:

  • 只能接收到部分通知:如果你同時發送多個通知,只有部分通知將會被接收,不用擔心!這正是我們想要的結果。當發送通知時APNS會為每一個開啟了推送通知的設備保持一個高質量服務(Quality of Service)隊列。這個隊列的大小是1,所以如果你同時發送多個通知,最後一個通知才會被發送。

  • 連接到APNS出現問題:出現這個問題的原因可能是你的防火牆阻塞了APNS所使用的端口。所以確保你的防火牆沒有阻塞住這些端口。另一個可能的原因是私鑰和CSR文件不正確。記住,每一個App ID有一個唯一的CSR和配對的私鑰。

解剖推送通知的基本原理

在進行任務3之前,需要理解一下你推送的通知,打開 newspush。php 文件理解發送一個通知的基本概念應該是怎麼樣的。

注意第32-40行,這就是用JSON格式編碼的裝載體。這就是實際上發送給APNS的東西。在我們當前的例子中,裝載體像下面一樣:

{
  "aps":
  {
    "alert": "Breaking News!",
    "sound": "default"
    "link_url" : "https://raywenderlich.com,
  }
}

對於一個不懂JSON數據的人來說,用{}括起來的塊相當於一個字典類型的數據。

這個裝載體是一個至少包含一項內容的字典,這項內容就是 aps, 它本身也是一個字典。在這個例子中”aps”包含”alert”,”sound”和”link_url”等字段。當接收到一個通知,就會顯示一個包含”Breaking News!”文本的提醒視圖,並且有標准的提醒音效。

“link_url”實際上是一個自定義的字段。你可以添加類似的自定義字段到裝載體中,並且它會被投送到你的應用。因為你並沒有在應用中處理這個字段,所以當前接收到這個鍵值對會什麼都不做。

你可以在aps字典中添加以下5個鍵(key):

  • alert。這個字段可以是一個字符串,就像當前的例子。或是是一個字典。如果是一個字典,可以是本地化的文本或者通知的其它部分。查看蘋果文檔所支持的key。

  • badge。這是一個將被顯示在應用圖標上的數字。你可以設置這個鍵為0來清除角標。

  • sound。通過設置這個建,你可以播放存放在App本地定制的通知提示音來取代系統默認的通知提示音。定制的通知提示音必須在30秒以內並且還有一些其它的限制,你可以查看蘋果文檔了解更詳細信息。

  • content-available。設置這個鍵為1,當前通知會變成靜默通知。這個部分會在這份教程的後面部分探索。

  • category。這個鍵定義了通知的分類,用於顯示定制通知所包含的交互行為。同樣,接下來會探索這部分的內容。

除此之外,你可以添加任意你想要添加的定制化數據,只要裝載體不超過4096個字節。

如果你玩夠了推送通知,接下來我們進入到下一個章節。

處理接收到的通知

在這個章節,你將會學習當App接收到通知後或者用戶點擊了通知應該如何執行什麼樣的操作。

當你接收到一個通知後會發生什麼

當你的App接收到一個通知,UIApplicationDelegate 的一個方法將會被調用。

需要根據接到收通知時App所處的狀態的進行不同的處理。

  • 如果你的應用當前不在運行,並且用戶通過點擊推送通知啟動應用,通知內容會通過 application(_:didFinishLaunchingWithOptions:) 方法的 launchOptions 參數進行傳遞。

  • 如果你應用當前正運行在前台,推送通知將不會被顯示。但是 application(_:didReceiveRemoteNotification:) 會被立即調用。

  • 如果你的應用正在運行,或者被掛起在後台,並且用戶通過點擊通知使應用進入前台 application(_:didReceiveRemoteNotification:) 方法會被調用。

在第一種情況下,WenderCast將到創建一個新的section,並直接打開以顯示到這個新建section。添加以下代碼到 application(_:didFinishLaunchingWithOptions:) 的末尾return語句之前。

// Check if launched from notification
// 1
if let notification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? [String: AnyObject] {
  // 2
  let aps = notification["aps"] as! [String: AnyObject]
  createNewNewsItem(aps)
  // 3
  (window?.rootViewController as? UITabBarController)?.selectedIndex = 1
}

這段代碼做了以下3件事:

  • 檢查 UIApplicationLaunchOptionsRemoteNotificationKey 鍵對應的值是否存在,如果存在,這個值應該就是你發送的通知裝載體。

  • 如果存在,獲取 aps 對應字典並傳給 createNewNewsItem(_:) 方法,這個方法根據接收的字典創建一個 NewItem,並刷新表格。

  • 改變tab控制器當前選中的tab索引值為1,也就是直接顯示新聞控制器視圖。

為了測試這部分代碼,你需要編輯WenderCast的scheme:

EditScheme.png

在 Run -> Info 下選擇 Wait for executable to be launched:

WaitForLaunch.png

這個選項會使調試器等待應用程序安裝直到應用程序第一次被啟動。

編繹運行,完成安裝後,發送一些新的動態。點擊通知以啟動App,啟動之後App會顯示一些新消息。

BuildAndRunFirstNews.jpg

注意 如果你突然接收不到通知,最有可能的原因是device token被改了。如果你刪除應用再重新安裝就有可能出現這種情況。確保你的device token是正確的。

為了處理另外兩種情況,添加以下代碼到 AppDelegate:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
  let aps = userInfo["aps"] as! [String: AnyObject]
  createNewNewsItem(aps)
}

這個方法直接創建了一個新的 NewsItem。現在你可以把scheme設置回自動啟動App。

編繹運行。保持App運行在前台,並選中新聞頁。發送一個通知,你可以看到消息奇跡般的顯示在視線內。

NewNews-281x500.jpg

就是這樣!你的App現在可以處理基本的推送消息。

一些需要注意的事情:很多情況推送通知可能會被遺漏。對於WenderCast應用來說是沒有問題的,因為裝滿消自己的列表對這個應用來說並不是那麼重要,但是一般來講你不應該把推送通知做為傳遞內容的唯一方式。作為備選項,推送通知應該僅僅只是指示當前有新的內容可以獲取並讓App從服務器下載這些新的內容。WenderCast應用在這方有一些局限性,因為它並沒有合適的服務端。

可交互的通知

可交互的通知允許你添加定制化的按鈕在通知上。你也許注意到郵件通知或者Twitter消息通知有一個讓你回復或者點贊的部位。

可交互的通知是你通過注冊通知時設置 categories 定義的.每一個通知分類都可以有多個預先自定義的交互。

一旦完成注冊,就可以發送這個分類的通知.當接收到通知相應的交互就可以被用戶獲取。

對於 WenderCast 應用,你將定義一個自定義”View”動作的”News”分類,自定義”View”允許用戶選擇查看,如果用戶選擇就會在App中直接顯示對應的消息詳細文章。

添加以下代碼到 registerForPushNotifications(_:): 的開頭。

let viewAction = UIMutableUserNotificationAction()
viewAction.identifier = "VIEW_IDENTIFIER"
viewAction.title = "View"
viewAction.activationMode = .Foreground

這段代碼創建了一個按鈕標題名為”View”的新交互通知,當交互通知被用戶觸發時打開App並讓其進入前台.這個交互動作的標識符是 VIEW_IDENTIFIER ,這個標識符被用於區分同一通知的不同交互動作.

添加以下人碼片段至前面代碼之後:

let newsCategory = UIMutableUserNotificationCategory()
newsCategory.identifier = "NEWS_CATEGORY"
newsCategory.setActions([viewAction], forContext: .Default)

這段代碼定義了一個新通知分類,設置交互動作為之前定義的”View”動作,設置標識符為” NEWS_CATEGORY”,這個標識符你是裝載體要包含的內容以用其指示當前通知屬於哪個分類.

最後,通過以下代碼,把新建分類傳遞給UIUserNotificationSettings構造方法。

let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: [newsCategory])

編繹運行,應用會注冊新通知設定。按Home鍵來退出當前應用,以使推送通知能夠顯示。

在你再次運行 newspush.php 之前,首先對指定的分類做一個改動。打開 newspush.php 修改通知裝載體使它包含通知的分類標識符:

$body['aps'] = array(
  'alert' => $message,
  'sound' => 'default',
  'link_url' => $url,
  'category' => 'NEWS_CATEGORY',
  );

保存並關閉newspush.php,然後運行以發送通知。如果一切進展順利,你可以下拉並輕掃顯示的通知你會看到View按鈕被顯示。

ViewAction-281x500.jpg

非常好,點擊”View”按鈕將啟動WenderCast但不會做任何事情。為了獲取通知裝載體顯示新的內容項,你需要在代理方法中做更多的操作。

處理通知交互動作事件

回到 AppDelegate.swift,添加另一個方法:

func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
  // 1
  let aps = userInfo["aps"] as! [String: AnyObject]

  // 2
  if let newsItem = createNewNewsItem(aps) {
    (window?.rootViewController as? UITabBarController)?.selectedIndex = 1

    // 3
    if identifier == "VIEW_IDENTIFIER", let url = NSURL(string: newsItem.link) {
      let safari = SFSafariViewController(URL: url)
      window?.rootViewController?.presentViewController(safari, animated: true, completion: nil)
    }
  }

  // 4
  completionHandler()
}

當用戶通過通知的交互動作打開應用時這個方法將會被調用.這看來起好像做了很多事,但是實際上沒有多少新的東西.這段代碼做了以下事情:

  • 獲取 aps 字典。

  • 根據獲取到的字典創建 NewItem 並跳到新聞頁。

  • 檢查以 identifier 為參數傳進來的交互動作的標識符。如果View交互動作的標識符和鏈接有效則用。SFSafariViewController 顯示這個鏈接內容。

  • 在處理完用戶交互動用之後調用系統傳遞給你的 completionHandler 回調。

編繹運行,退出App。發送通知。但請確保下面的URL中有效的:

$ php newspush.php 'New Posts!' 'https://raywenderlich.com'

點擊通知的交互動作,在WenderCast應用啟動後會立即展示Safari控制器。

SafariVC-281x500.jpg

恭喜,你剛剛已經完成了可交互通知的實現!嘗試多發送幾次通知,並用不同的方法打開通知觀察通知的展現行為。

靜默推送通知

靜默推送通知可以靜默方式的喚醒你的App並讓它在後台執行任務。WenderCast可以利用這個特性悄悄地刷新播客列表。

正如你所想象的,配合合適的服務端這個功能會非常有用。你不需要不斷的主動獲取數據,當有數據可獲取時僅僅只需要發送一個靜默通知。

開始之前進入 App Settings -> Capabilites 並打開 WenderCast的 Background Modes. 檢查最後一個選項,Remote Notifications 是否勾選。

1463990284465137.png

現在你的App接收到某個靜默通知就可以在後台喚醒.

在AppDelegate內,用下面更強大的版本替換 application(_:didReceiveRemoteNotification:) 方法:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
  let aps = userInfo["aps"] as! [String: AnyObject]

  // 1
  if (aps["content-available"] as? NSString)?.integerValue == 1 {
    // Refresh Podcast
    // 2
    let podcastStore = PodcastStore.sharedStore
    podcastStore.refreshItems { didLoadNewItems in
      // 3
      completionHandler(didLoadNewItems ? .NewData : .NoData)
    }
  } else  {
    // News
    // 4
    createNewNewsItem(aps)
    completionHandler(.NewData)
  }
}

這段代碼:

  • 檢查 content-available 是否為1,以確定是否是靜默推送。

  • 刷新播客列表,因為需要訪問網絡所以刷新列表是異步的。

  • 當刷新完列表,調用 completionHandler 回調方法,讓系統知道數據是否已經下載。

  • 如果不是靜默通知,假定它是消息並創建一個新的消息項。

必需要確保 completionHandler(_:) 方法被調用並傳遞真實的是否獲取到數據的結果。系統會根據回調計算耗電量和App在後台的時間,系統會根據需要調節App的耗電量以及在後台的時間。

以上就是這段代碼所做的事。現在你可以用 contentpush.php 給你的應用發送一個靜默通知。請務必確認以下設置腳本的正確性:

// Put your device token here (without spaces):
$deviceToken = '43e798c31a282d129a34d84472bbdd7632562ff0732b58a85a27c5d9fdf59b69';
// Put your private key's passphrase here:
$passphrase = 'WenderCastPush';

在終端直接運行:

$ php contentpush.php

如果一切順利,什麼事都不會發生。為了看到這段代碼的運行結果,與之前設置的一樣結果必須把scheme設置為”Wait for executable to be launched”並在 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 方法旁邊打上斷點,以確認這個方法會被調用。

路在何方?

恭喜你已經完成了這份推送通知教程的內容並且WenderCast應用也有全部的推送功能!

你可以在這裡下載完整的工程。記住為了能讓工程正常運行你仍然需要更改Bundle ID和證書。

推送通知功能對於現在的App已經是一個不可或缺的部分,但如果你發送的通知太頻繁用戶仍然會調整你的通知請求許可。對於一個深思熟慮的設計,推送通知會讓你的應用保持足夠的用戶粘性!

cat-1136365_1280-768x512.jpg

這只貓接收到“推送通知”後它就知道晚餐已經准備好了。

我希望你能喜歡這份推送教程。如果你有任何問題,你可以在下面的評論中隨意提問。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved