你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> Apple Watch兩個月開發的一些收獲總結

Apple Watch兩個月開發的一些收獲總結

編輯:關於IOS
[收起] 文章目錄
  • 1. Watch Main App
  • 2.Notification
  • 3.Glance
  • 4.總結
  • 作者信息

 

Apple Watch即將於4月下旬發售,而Watch App的開發已成為iOS開發的熱點。本文作者通過Watch App的實際開發經驗,將其中的一些注意事項總結分享給大家。以下為正文:

接觸Apple Watch相關的開發工作已經差不多快三個月時間了,每天都會去逛逛WatchKit蘋果的開發者論壇,看看最近都有哪些其他開發者po出來的問題。我自己也遇到不少問題,其中很多都是我自己摸索著解決掉的。

蘋果公布的關於Apple Watch的信息很多,用於開發已經足夠,但一切感覺都是在抹黑前行,因為無法進行真機測試,包括Handoff,也包括語音輸入,以及發布會上的那個類似Emoji 的表情都是些什麼。

自己來現在的公司實習到今,主要做的工作幾乎都和iOS8新特性有關,畢竟現在公司這個項目實在是太成熟了,摸熟悉也需要一個過程。包括之前的 Today Widget,到後來的Handoff,包括因為要適配iPhone6做的適配方面的調研等等,都是從去年WWDC之後的新事物,轉眼就到2015年的 WWDC了,不知道今年會有哪些革新的新事物。

閒話說到這裡吧,是時候總結一下這兩個月的收獲和掉坑了。

目前開發者網站上的這幾部分我覺得是開發Watch 必須學習幾遍的東西,還有蘋果開發者論壇也是一個不錯的交流地方。

  • WatchKit Framework Reference
  • WatchKit Development Tips : Optimize your WatchKit apps with these tips and best practices.
  • Apple Watch Programming Guide
  • Developer Forum

1. Watch Main App

在iPhone上,主程序是大哥,其他的小擴展必須讓路,但是在Watch上,是不是大哥還要看這個APP主要的功能。如果是一個閱讀性質的 APP,主程序在手表上作用還真不大,例如閱讀新聞等等。如果是這類的應用,想在Watch上出彩,或者讓用戶使用的次數多一些,就要靠良好的 Notification體驗,以及極其方便用戶生活的Glance了。

(1)以Page-Based方式啟動Watch App

Apple Watch兩個月開發的一些收獲總結

如上圖,現在手上要做的一個交互是,App啟動的時候是六個頁面,用戶可以左右滑動來切換,這裡就需要在MainInterfaceController中使用下邊這個方法了。

 [WKInterfaceController reloadRootControllersWithNames:
_controllersArrays contexts:_contextsArray];

在Watch上頁面之間轉換傳值,很重要的一個紐帶就是這個context,傳遞有用的信息和標識,這個方法中,我傳遞進入六個controller的interface builder identifier,以及事前拼好的六個context。

因為Watch App 的打開可以是幾種不同方式的,可以寫一個統一的方法[self showController],在這個方法中去選擇啟動哪一個具體的Controller。我在.h文件中定義了一個枚舉來定義不同的啟動方式:

typedef enum  {
    WKOpenForNormal,      //普通打開
    WKOpenForComment,     //打開評論頁
    WKOpenForFavorite,    //打開收藏頁
    WKOpenForGlance   //打開來自glance的內容
} WKOpenType;

因為用戶如果選擇了點擊Glance 來查看具體的內容的話,Glance和MainApp是通過Handoff來實現通信的,我們可以在入口的控制器中的:

- (void)handleUserActivity:(NSDictionary *)userInfo;

這個方法中去將WKOpenType賦值成WKOpenForGlance。

當然了,如果是從Notification來的,我們完全可以通過:

- (void)handleActionWithIdentifier:(NSString *)
identifier forRemoteNotification:(NSDictionary *)remoteNotification;

這個方法來根據具體的用戶點擊的動作來區分不同的打開方式。

這裡比較難處理的是,如果用戶是從Glance進來的,退出這個控制器,還是要顯示那六個頁面的,這裡我的解決方法是注冊通知。在出來的控制器中的 - (void)didDeactivate;方法中post出來通知,來讓主控制器重新打開六個Page頁面。Notification同Glance。

(2)Watch App 與Host App 聯合調試

因為程序中多處用到了下邊這個方法,因此主程序和Watch App 聯合調試就顯得非常必要了,在Xcode的一個新beta 的release note中蘋果介紹了一種方法。

+ (BOOL)openParentApplication:(NSDictionary *)userInfo reply:
(void(^)(NSDictionary *replyInfo, NSError *error)) reply;
  1. 首先run 起來Apple Watch App在模擬器中。
  2. 在iphone 模擬器中啟動 demo App。
  3. Xcode - Debug - Attach to Process 裡找到host app 線程,Attach上。

完成以上三個步驟,主程序和手表程序上的端點都可以進行調試。

(3)申請數據方面

在開發初期,我是在extension中進行數據的申請,這樣嘗試了一段時間之後發現性能上優化的空間不大,而且寫出了很多重復的代碼。復用項目中 已有的代碼是我最好的選擇,尤其是一些第三方用pod管理的庫,但是考慮到公司的項目已經是非常成熟的了,一些管理的第三方庫無法正常的使用,進而又去考 慮寫一個共用的框架,由於時間問題,項目有點大,抽筋抽骨的不是很合適,所以決定充分發揮openParent這個方法,將申請數據這塊放在主程序中,順 便將所有需要“問”主程序的東西全部整理到一個類中,這樣就可以充分發揮老代碼的作用。

數據策略大致如下:首先為了優化Watch App 的啟動速度,采用後台申請數據存起來,Watch每次去使用就可以了,最後處理一下冷啟動的問題,這種情況是當安裝了我們的軟件,沒有在iPhone上打 開過,直接打開Watch上的程序的時候已然有數據,這麼做的話除了第一次會啟動的稍微慢一點點之外,剩下的啟動速度就會快很多。

具體用到的方法是:

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:
(void (^)(UIBackgroundFetchResult result))completionHandler NS_AVAILABLE_IOS(7_0);

我和同事做到這裡的時候,就感覺是一個iPhone當做了服務器,而Watch則是一個終端,有什麼需要的數據,我們兩個人設計好協議,通過 openparent這個方法溝通。比如說,軟件運行當中如果想要知道一個用戶是否登錄了,因為沒有登錄是沒有某些功能的,那麼這個時候通過 openparent咨詢一下isLogin就好,判斷一下是否登錄。

Demo中 watch 端代碼實現如下:

[WKInterfaceController openParentApplication:@{@"type":@"isLogin"} 
reply:^(NSDictionary *replyInfo, NSError *error) {}

Demo中 iphone 服務端代碼實現如下:

#pragma mark - WatchKit Data
-(void)application:(UIApplication *)application 
handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply
{
    NSString *type = userInfo[@"type"];
    NSDictionary *para = userInfo[@"para"];
    ...
    ...
    NSDictionary *replyInfo;
    if ([type isEqualToString:@"isLogin"]) {
        int random = arc4random()%10 + 1;
        NSString *whetherLogin = @"";
        if (random == 1) {
            whetherLogin = @"YES";
        }else
        {
            whetherLogin =@"NO";
        }
        replyInfo = @{@"whetherLogin":whetherLogin};
    }
    else if ([type isEqualToString:@"isFavorite"])
    {
        ...
        ...
        ...
    reply(replyInfo);
}

Demo中有三種協議,分別是是否登錄,回復信息,是否收藏,當然都是假的,根據項目需求來進行改變,務必注意的是每一種情況都要回調reply(replyInfo);,否則這個方法實際上會響應失敗

而實際上,項目當中需要在Watch上顯示很多圖片的,這個就需要異步的申請一下,首要想到的還是SDWebImage這個經典框架,這裡就可以在openParent裡使用將data請求到,然後返回給Watch。

PS:最後的最後,我們發現使用App Group來通信數據更加的有效率,因此一部分數據的請求采用了App Group來實現。

(4)TableView 在Watch 上的使用

在SDK發布的初期,我以為新控件之一WKInterfaceGroup可以點擊,因為目前來看watch上是沒有圖層的概念的,復雜的UI布局是 相當困難的,布局方式和之前有很大的區別,包括在故事板中的布局方法。當初為了實現產品給過來的UI布局也是腦洞大開啊,比如各種嵌套Group,為了要 實現demo中主頁的這種感覺,我很自然的想到了,放一個group,背景放圖片,其他控件放在group上就好了,解決了無法實現控件在控件之上的問 題。但是這就需要group可以點擊,盼星星盼月亮之後,Xcode6.2正式版出來之後徹底斷了我這個念頭,沒辦法,只能通過另一個控件 WKInterfaceTable來實現了,每一頁只有一行不就可以了麼,只能這麼干了。

WKInterfaceTable和UITableView使用上還是有一些不同的,也比UITableView的使用方便了很多。

首先你需要去定義一個Row類,這個Row類相當於一個cell,在這個Row上去布局,如果你的表格中呈現數據的方式不一樣,那就要定義不同的Row類。

定義好之後,調用的時候需要使用如下方法:

#pragma mark - UI
- (void)setUpUI
{
    [self.newsRowTabel setNumberOfRows:1 withRowType:@"RowForOneNews"];
    for (int i = 0; i < self.newsRowTabel.numberOfRows; i++) {
        JRWKNewsRow *newsRow = [self.newsRowTabel rowControllerAtIndex:i];
        [newsRow.newsCategory setText:[NSString stringWithFormat:@"第%ld張",_index+1]];
    ...
    ...
    }
}

RowType唯一標識了一個Row類,這裡我設置了只有一行,期間設置Row類中每一個屬性的UI數據。

響應點擊事件需要去實現:

#pragma mark - Table Row Select
-(void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex
{
    NSDictionary *contextDic = @{@"PicName":_picName,@"index":[NSNumber numberWithInteger:_index]};
    [self presentControllerWithName:WKNEWSDETAILCONTROLLERIDENTIFIER context:contextDic];
}

這裡去指定具體要呈現出來的是哪一個Controller。

如果表格中的一行不能點擊的話,在故事板中設定的時候把selectable勾選掉就可以了。

Apple Watch兩個月開發的一些收獲總結

(5)數據在Controller 間的傳遞

API中的幾個關於Controller切換的方法當中幾乎都有context參數,也就是說傳遞數據由我們決定了。在十二月份剛開始寫程序的時 候,我傳遞的是一個很大的字典,發現在程序啟動的時候非常的慢,後來決定寫一個模型管理類,controller之間只需要傳遞一個index就可以了。 在demo中保留了完整的類。

(6)關於HandOff

HandOff在iOS8之後出現,著實是為了Apple Watch量身打造的好麼,實在是太應景了,因此在Watch上合理的運用handoff 是一個順理成章的事情,而WKInterfaceController也帶上了相關的一些方法,實際上是要比iphone上的簡單易用一些的。

另一方面,在Glance界面,進入到主App上的時候,handoff也起了決定性的作用,通過handoff將具體的信息交給主App去處理。

主要有兩個Api,這個是update了全局的Activity,將我們需要傳遞的信息打包成一個userinfo即可。

- (void)updateUserActivity:(NSString *)type userInfo:
(NSDictionary *)userInfo webpageURL:(NSURL *)webpageURL;

下面這個我還記得是開發者watchkit論壇裡有一位開發者問過這個問題,在watchkit裡怎麼沒有干掉Activity這一個方法。後來蘋 果的工程師估計是采納了。但實際的效果來看,這個方法作用不大,例如在公司的項目中,幾乎每一個頁面都是需要handoff的,給它invalidate 之後,iphone左下角出現logo就會出現異常甚至是不出現的情況。因此如果不是已經很明確的話,輕易的不要用這個方法。

- (void)invalidateUserActivity;

總之,Handoff是Watch和iPhone溝通的絕佳方式之一,蘋果也一直很鼓勵使用SDK新出的一些東西來補充自己的App的。不要再幻想(至少是現在)通過Watch上的一個按鈕能夠使得iPhone 上的Host App 能夠打開並且顯示在前台了。

(7)其他一些Tips

(1).dynamic notification中蘋果是希望用戶在通知中就把所有的信息都看完的,而不希望用戶點擊內容本身(實際上也是不能點擊的)再進入到Watch app 內查看這個通知的內容的,恰恰相反的是,glance 的交互理念是相反的,也就是蘋果估計用戶點擊glance頁面本身(實際上是可以點擊的)進入到Watch app中進行繼續深度閱讀的。

(2).關於WKTextInputMode,一開始選擇的是WKTextInputModeAllowAnimatedEmoji,後來發現這個 是動態的大表情,返回的是這個大表情的data,不太適合我們一一對應到iphone上的emoji表情,於是後來切換到了 WKTextInputModeAllowEmoji。而WKTextInputModePlain只是顯示了我們所“推薦的”那些回復文本選項。

typedef NS_ENUM(NSInteger, WKTextInputMode)  {
    WKTextInputModePlain,       
// text (no emoji) from dictation + suggestions
    WKTextInputModeAllowEmoji,      
// text plus non-animated emoji from dictation + suggestions
    WKTextInputModeAllowAnimatedEmoji,  
// all text, animated emoji (GIF data)
};

(3).- (void)becomeCurrentPage; 這個方法主要是在page based頁面當中,如果第三頁在啟動的時候你想讓它先出來,就要標識好,在awake裡邊獲取到之後,調用這個方法,注意的是,這個第三頁不是立馬就出 現在手表的表盤之上的,而是從第一頁蹦到第二頁,然後再第三頁這樣轉的。

(4).推薦一個很好用的工具,叫做Bezel,它能夠將模擬器中運行的watch app 映射到真實的手表裡,表帶的樣式也分38mm以及42mm,有很多種,可以更好的查看自己的App在真實手表上的樣子。更換表帶也很方便,直接拖著下邊的 某一個樣式到Bezel上就自動換了。舉個例子,在開發的時候曾想左右留邊,但是放在Bezel上就會發現手表自帶黑邊,於是留下的左右邊就是很多余了。

Bezel 下載地址,頁面內包含N多種表帶

Apple Watch兩個月開發的一些收獲總結

2.Notification

從目前來看,手表上出現push應該是隨著手機一起來的,也就是同時去顯示在這兩個設備上,除非一切外力因素,比如手表關閉了抬手查看通知等。在之 前的blog中提到過定義category來區分推送通知,如果沒有定義category的故事板的話,就會在手表上顯示一個系統默認的簡短的通知。上邊 說道,蘋果還是鼓勵在notification中將該閱讀的內容都閱讀完,即使增加按鈕也要是一些比較簡單的操作,比如說一個日程安排的軟件,來了一個 push,一個done,一個delete,加上系統的cancel,就可以了。

我嘗試了在Dynamic notification中申請了一個圖片資源,發現系統就選擇去顯示Static notification,因此在notification controller內進行的任務的能力有限,這個在開發的時候要慎重。

開發的時候,Xcode自動生成的Payload很重要,可以定義多個payload來進行相應的模擬,搭配不同的category,不同的category故事板。

3.Glance

我依然認為Glance 的地位在Watch上是最重要的,至少在第三方獨立app登上Watch前,Glance應該是用戶使用最頻繁的一個功能。因此Glance上要呈現的東 西不能太少,也不能太多,一定要簡明扼要,要呈現出最重要的一些東西。例如說如果自己的App不是以天氣為主的,放一個天氣溫度什麼的就不是很合適,系統 的天氣和地圖軟件還是非常出色的,因此還是在Glance 只體現自己App裡邊獨特的東西最好。

另外,Glance的UI布局是很講究的,如果可以盡量要按照Xcode 給的Upper和Lower的模板進行UI布局。不能使用任何可以操作的空間,例如按鈕這樣的,因為Glance就一頁(可以滾動也是禁止的),有點像是 渲染出來的一張圖片似的,因此加個按鈕是沒有意義的。

Apple Watch兩個月開發的一些收獲總結

同Notification,Glance controller 中進行任務的能力也比較有限,因為眾多的Glance會一同呈現出來,用戶翻騰著每一個app 的Glance,這就要求用戶一掃之後就要呈現出來,一個比較好的解決方法就是Glance要呈現的數據提前的申請好,用的時候拿出來,具體實現的方法也 有很多。比如上邊提到的App Group。

Glance 以及主App的通信是依靠Handoff來實現的,也就是說用戶點擊了Glance這個頁面之後,進入到主App,要做的事情需要根據傳過來的userinfo來決定的,主要就是下邊這個方法。

[self updateUserActivity:XXXXX userInfo:userInfo webpageURL:nil];

在入口controller中實現方法,決定啟動什麼頁面,呈現什麼內容,可以放在willActivate裡邊。記住的是請求數據這塊一定要放在awake裡邊,不要放在willActivate裡邊。

-(void)handleUserActivity:(NSDictionary *)userInfo
{
    wkOpenType = JRWKOpenForGlancedemo;
    if (userInfo) {
        NSString *sourceString = [userInfo objectForKey:@"Source"];
        NSString *picName = [userInfo objectForKey:@"PicName"];
        if ([sourceString isEqualToString:@"Glance"]) {
            _glancePicName = picName;
        }
    }
}

根據wkopentype決定啟動頁面。

 switch (wkOpenType) {
        case JRWKOpenForGlancedemo:
            //glance page
            break;
        case JRWKOpenForNotificationdemo:
            //notification page
            break;
        default:
            [self showPageBaseddemoController];
            //默認啟動
            break;
}

Glance 在demo中的表現形式,demo已經整理好,放在了自己的Github上。

AppleWatchDemo

Apple Watch兩個月開發的一些收獲總結

4.總結

其實WatchKit的東西真不多,更多的是在一個新的平台遇到的各種問題和bug是最讓人頭疼的。隨著真機的即將到來,開發工作也不再是抹黑前 行,這些都是利好的消息。不知道什麼時候可以有獨立的第三方應用的支持,也不知道WatchKit會豐滿到什麼程度,總之我個人還是很看好Watch的未 來的,畢竟蘋果引領的穿戴設備的頭。

 

作者信息

劉瑞,中國科學技術大學蘇州研究院在讀碩士,喜歡科技產品,也喜歡制作開箱、體驗視頻。大三起開始自學iOS開發。

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