iOS之widget開發(Today Extension)

蘇小妖發表於2017-06-05

前言

extension是iOS8新開放的一種對幾個固定系統區域的擴充套件機制,它可以在一定程度上彌補iOS的沙盒機制對應用間通訊的限制。

extension的出現,為使用者提供了在其它應用中使用我們應用提供的服務的便捷方式,比如使用者可以在Today Extension中檢視應用展示的簡略資訊,而不用再進到我們的應用中,同樣可以快捷操作app的功能,這將是一種全新的使用者體驗。

今天我們介紹一下給工程新增Today Extension的步驟。

新增Today Extension工程

在原有的工程基礎上,想要使用Today Extension,我們需要建立一個新的target,點選File-->New-->Target-->Today Extention,如下圖所示:

iOS之widget開發(Today Extension)
新增Target

iOS之widget開發(Today Extension)
選擇Today Extension

新增成功後專案的目錄會如下圖所示:

iOS之widget開發(Today Extension)
工程目錄

執行專案會看到如下圖所示的效果:

iOS之widget開發(Today Extension)
執行效果

定製UI

由於我習慣使用純程式碼寫UI,所以我會選擇刪除預設建立的MainInterface.storyboard,並在info.plist中刪除NSExtensionMainStoryboard,新增NSExtensionPrincipalClass為TodayViewController,如下圖所示:

iOS之widget開發(Today Extension)
配置controller

我們可以使用以下方法配置檢視的大小

//配置Today Extension展示檢視的大小
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 100);複製程式碼

實現下面的協議,配置邊距,否則會發現一個問題:繪製的內容與左側邊界有一定距離。

- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets {

    //配置邊距為0
    return UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);

}複製程式碼

我們建立一個lable來充滿檢視,並且點選可開啟我們的app

//Today Extension的頁面加一個可點選開啟containingAPP的label
UILabel *openAppLabel = [[UILabel alloc] init];
openAppLabel.textColor = [UIColor colorWithRed:(97.0/255.0) green:(97.0/255.0) blue:(97.0/255.0) alpha:1];
openAppLabel.backgroundColor = [UIColor clearColor];
openAppLabel.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 100);
openAppLabel.textAlignment = NSTextAlignmentCenter;
openAppLabel.text = @"點選開啟app";
openAppLabel.font = [UIFont systemFontOfSize:15];
[self.view addSubview:openAppLabel];

openAppLabel.userInteractionEnabled = YES;
UITapGestureRecognizer *openURLContainingAPP = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(openURLContainingAPP)];
[openAppLabel addGestureRecognizer:openURLContainingAPP];複製程式碼

開啟app

Today Extension只能通過openURL的方式來調起app,並且需要在info.plist檔案中配置引數URL types,
app工程中配置如下

iOS之widget開發(Today Extension)
app schemes

Today Extension如下圖

iOS之widget開發(Today Extension)
跳轉URL types設定

URL identifier為app的bundle ID,URL Schemes配置為app的scheme
並且呼叫以下程式碼來開啟app

//通過openURL的方式啟動Containing APP
- (void)openURLContainingAPP
{
    //scheme為app的scheme
    [self.extensionContext openURL:[NSURL URLWithString:@"scheme://xxxx"]
                 completionHandler:^(BOOL success) {
                     NSLog(@"open url result:%d",success);
                 }];
}複製程式碼

demo程式碼,由於後面的步驟是需要蘋果開發者賬號才能操作,所以demo的程式碼到這裡為止。

資料共享

首先需要去蘋果開發者中心的APP Groups中建立一個APP Group,命名方式"group.com.companyName.xxx",如下圖

iOS之widget開發(Today Extension)
建立App Group

完成之後你還要做以下修改

  1. 編輯你的contain app的APP ID,Service中選中App Groups,並且點選右邊的Edit按鈕選中剛剛建立的group,返回後,點選Done完成APP ID的編輯
  2. 此時contain app的Provisioning Profiles檔案會顯示為無法使用,需要更新下檔案,並且下載下來覆蓋安裝

Today Extension工程與app工程的配置都如下圖所示

iOS之widget開發(Today Extension)
App Groups設定

通過App Groups提供的同一group內app共同讀寫區域,可以用NSUserDefaults和NSFileManager兩種方式實現Today Extension和containing app之間的資料共享。

通過NSUserDefaults共享資料

- (void)saveDataByNSUserDefaults
{
    NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.xxx.xxx"];
    [shared setObject:@"test" forKey:@"widget"];
    [shared synchronize];
}

- (NSString *)readDataFromNSUserDefaults
{
    NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.xxx.xxx"];
    NSString *value = [shared valueForKey:@"widget"];

    return value;
}複製程式碼

通過NSFileManager共享資料

- (BOOL)saveDataByNSFileManager
{
    NSError *error = nil;
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.xxx.xxx"];
    containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/test"];

    NSString *value = @"test";
    BOOL result = [value writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&error];
    if (!result) {
        NSLog(@"%@",error);
    } else {
        NSLog(@"save value:%@ success.",value);
    }

    return result;
}

- (NSString *)readDataByNSFileManager
{
    NSError *error = nil;
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.xxx.xxx"];
    containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/test"];
    NSString *value = [NSString stringWithContentsOfURL:containerURL encoding:NSUTF8StringEncoding error:&error];

    return value;
}複製程式碼

這樣就實現了Today Extension與app的資料共享

真機除錯與打包

我們把Today Extension當作一個單獨的app,各自有自己的App ID和Provisioning profile. 在Xcode裡是兩個Target給不同的target設定自己的bundleID和Provisioning profile。所以你需要按以下步驟操作,才能真機除錯以及打包

蘋果開發者中心操作以下步驟

  1. 需要為Today Extension建立一個APP ID,一般命名方式為你的contain app的bundle id加上你建立的Today Extension工程名"com.companyName.xxx.xxx",App Services中勾選上App Groups,完成建立。如下圖
    iOS之widget開發(Today Extension)
    Today Extension APP ID設定
  2. 去Provisioning Profiles中建立Today Extension對應的profile檔案,下載下來,安裝,真機除錯和打包需要用到,如下圖
    iOS之widget開發(Today Extension)
    Today Extension profile檔案
  3. 將Today Extension的bundleID修改為剛剛為Today Extension建立的APP ID
  4. Today Extension版本號與contain app配置一致,否則稽核上傳的時候會有警告
  5. 打包或者真機除錯的時候contain app與Today Extension選擇各自的profile檔案。

完成以上的準備工作之後,我們就可以開始真機除錯以及打包了。

總結

本篇暫時只是Today Extension簡單的功能實現,我會在後面更新iOS10的適配,以及其他功能使用。如果有錯誤的地方歡迎指出~謝謝~

擴充套件閱讀

  1. WWDC2014之App Extensions學習筆記

希望對您有幫助,如果文章中有問題,歡迎評論留言~,謝謝支援~歡迎關注,我會在空餘時間更新技術文章~

相關文章