iOS Action Extension開發(fā)教程顷啼,實現(xiàn)跨APP的數(shù)據(jù)共享

iOS8.0加入了擴展,iOS10蘋果又增加了很多擴展昌屉。在今后钙蒙,程序中會集成越來越多的擴展功能。

今天主要來模仿1password實現(xiàn)在其他APP登錄時自動填充賬號间驮、密碼躬厌。通過這一功能開發(fā)了解擴展。

這是一個很有意思的功能竞帽。

我們先來看功能實現(xiàn)效果扛施。

fdfasiiyiuyuiyi.gif

1passwrod是一款密碼管理類app,我們可以在登錄時喚醒1password并獲取到相應的賬號密碼屹篓,然后填充到輸入框中以實現(xiàn)賬號密碼的自動填充疙渣、登錄。

這種app之間的互相訪問堆巧、數(shù)據(jù)共享看起來與我們以往的開發(fā)經(jīng)歷所不同妄荔。這種功能實現(xiàn),不僅使APP更加靈活恳邀,還提升用戶體驗懦冰。

如何實現(xiàn)的呢,看完這篇文章谣沸,你也能學會刷钢。

先來創(chuàng)建一個demo工程,工程名為ExtensionDemo乳附。

網(wǎng)上的文檔有很多内地,但基本都以一個簡單的demo為主伴澄,在我創(chuàng)建的demo中,涉及到了宿主應用和應用擴展的數(shù)據(jù)庫共享阱缓、類共享非凌、xib共享、以及宿主應用和應用擴展荆针、應用擴展和host app的相互通信敞嗡。把需求實現(xiàn)過程中遇到的坑全部描述清晰,幫助小伙伴少走彎路航背。

開始之前喉悴,我們需要了解一些理論知識。
host app:通過點擊系統(tǒng)分享菜單中的插件圖標調(diào)起擴展程序玖媚,在gif圖片中箕肃,喚起1password的應用就是host app。
宿主應用:也叫Containing App今魔,簡單點說勺像,我們創(chuàng)建一個Xcode工程,然后運行項目错森,這個就是宿主應用吟宦。
應用擴展:也叫App Extension,打包運行在手機上時涩维,會隨著宿主應用一起安裝在手機上督函。詳細來說,gif圖中喚起的應用并不是1password本身激挪,而是1password的應用擴展辰狡。是獨立于宿主應用之外的。

總結(jié)一下:應用擴展就是宿主應用和host app溝通的橋梁垄分,使宿主應用和Host App的數(shù)據(jù)共享成為可能宛篇。

他們的關系圖如下:

圖1.jpg
圖2.jpg

宿主應用 & 應用擴展

好,開始薄湿。

宿主應用和應用應用是在一個工程下叫倍,用戶安裝APP后,如果工程內(nèi)有應用擴展豺瘤,應用擴展也會默認安裝在用戶的手機上吆倦。

先來看一下宿主應用的顯示效果。

iPhone6 Plus

工程文件

工程文件

這里為了方便坐求,使用PasswordDBTool來操作數(shù)據(jù)庫蚕泽,沒有使用Key-Value式的存儲,不過這里不是本次的重點。數(shù)據(jù)庫相關下次來寫须妻。

好仔蝌,到這里,宿主應用所需要的東西我們都搞定了荒吏。接下來敛惊,開始應用擴展的開發(fā)和相應的配置。

在之前绰更,我們已經(jīng)了解到瞧挤,應用擴展屬于應用的擴展。擴展是iOS8.0加入的一個非常強大的功能儡湾。接下來開始在項目中加入擴展皿伺。

1、添加擴展Target

Snip20160808_148.png
Snip20160808_149.png
Snip20160808_150.png
Snip20160808_151.png

2盒粮、操作完的工程文件

Snip20160808_152.png
Snip20160808_153.png

這些都是添加完擴展target后系統(tǒng)默認為工程生成的。

當然奠滑,ActionViewController的.h.m文件和MainInterface.storyboard文件我們都可以隨便的對其更改丹皱。其實這三個文件和我們平時創(chuàng)建使用的類文件和storyboard文件并無兩樣。同樣支持拖線等操作宋税。

3摊崭、接下來我們看一下ActionViewController的.h和.m文件中的代碼內(nèi)容。

ActionViewController.h
ActionViewController.m

系統(tǒng)創(chuàng)建的ActionViewController默認繼承自UIViewController杰赛,當然我們也可以對這里進行更改呢簸,讓其繼承自UITableViewController以便之后的開發(fā)。

重點來講一下圖2中的代碼內(nèi)容乏屯。

(1)self.extensionContext
command+鼠標左鍵點進去看看根时,發(fā)現(xiàn)是這樣的。

Snip20160808_156.png

發(fā)現(xiàn)self.extensionContext是NSExtensionContext對象辰晕。見名知意蛤迎,extensionContext即擴展上下文,用來聯(lián)系宿主應用和應用擴展含友,它們倆之間的通信就是靠extensionContext替裆。

(2)NSExtensionItem
待處理的數(shù)據(jù),宿主應用和應用擴展之間通信的數(shù)據(jù)(參數(shù)等)我們可以放到NSExtensionItem對象中窘问。在各自的應用中通過NSExtensionItem獲取通信數(shù)據(jù)辆童。

(3)NSItemProvider
確切來說,宿主應用和應用擴展之間需要傳遞的數(shù)據(jù)是放在NSItemProvider對象中的惠赫。
那么把鉴,NSItemProvider對象是如何進行數(shù)據(jù)存儲的?重點在這里儿咱。

Paste_Image.png

通過NSItemProvider對象的
loadItemForTypeIdentifier:options:completionHandler:方法纸镊。
這里有一個特別需要注意的點倍阐,就是第一個參數(shù)的傳值。command+鼠標左鍵點擊第一個參數(shù)KUTypeImage逗威,進去會發(fā)現(xiàn)有幾十個這樣的參數(shù)峰搪。當然,每一種參數(shù)的含義都不相同凯旭,這里不一一詳解概耻。如果這里的參數(shù)值傳的是KUTypeImage則相應的,宿主應用傳遞過來的數(shù)據(jù)是一個圖片罐呼。如果這里的參數(shù)值傳的是kUTTypePropertyList鞠柄,相應的,宿主應用傳遞過來的數(shù)據(jù)可能是一個字典嫉柴。
但是在我們的demo中厌杜,我們不使用系統(tǒng)提供的這些參數(shù),而使用自定義參數(shù)计螺。格式如下:

Snip20160808_158.png

具體是什么含義會在下面陸續(xù)講解夯尽。因為這里需要host app協(xié)同操作才能看的更明白。

應用擴展

我們都知道登馒,iOS應用具有沙盒機制匙握。app之間是不能進行數(shù)據(jù)共享的。而在文章開頭展示的gif圖卻給我們造成一種假象陈轿,即我們在app中可以去訪問其他app的數(shù)據(jù)圈纺,有種“app之間可以進行數(shù)據(jù)共享”的錯覺。而這種錯覺就是應用“擴展”給我們造成的麦射,擴展使app之間的數(shù)據(jù)共享成為了一種可能蛾娶。使app變得更加靈活。

現(xiàn)在潜秋,我們要實現(xiàn)的需求是這樣的:在host app中喚起應用的擴展茫叭,host app需要傳給應用擴展一個URL參數(shù),應用擴展根據(jù)host app傳遞過來的URL參數(shù)在宿主應用內(nèi)的數(shù)據(jù)庫中查找符合條件的數(shù)據(jù)半等,再把符合條件的數(shù)據(jù)回傳給host app揍愁。

整個流程是這樣的。

20150114200552609.jpg

在整個通信過程中杀饵,難點在于宿主應用和應用擴展的數(shù)據(jù)共享莽囤,不僅僅是數(shù)據(jù)共享,可能還需要共享一些開發(fā)文件切距,比如類文件朽缎、xib、storyboard等。不要以為宿主應用和應用擴展同屬于一個工程項目话肖,它們兩個就可以共同使用項目內(nèi)的數(shù)據(jù)和所有文件北秽。這是錯誤的。那么最筒,宿主應用和應用擴展如何進行數(shù)據(jù)共享贺氓?我們需要創(chuàng)建一個共享域,當然床蜘,蘋果早就給我們準備好了辙培,我們只需要配置一下即可。

1邢锯、配置共享域
(1)配置宿主應用共享域

Snip20160808_160.png
Snip20160808_163.png

點擊ON后扬蕊,其實App Groups這里是空的,因為我之前做項目有配置過共享域丹擎,所以在選擇證書的時候尾抑,系統(tǒng)會把證書配置過的共享域都給我自動加載了出來。如果這里是空的蒂培,就點擊下面的+號再愈,添加一個共享域。

這時毁渗,Xcode會彈出提示框,讓你給共享庫起一個名字以辨別单刁,因為有些項目可能需要不只一個共享域灸异,如果項目支持Apple watch,就需要一個新的共享域支持Apple watch羔飞。共享域的名字以group.開頭肺樟,名字自己起。

Snip20160808_162.png

OK逻淌,添加完共享域后么伯,新的共享域就出現(xiàn)在了APP Groups中,選中它卡儒。

到這里田柔,宿主應用的共享域配置告一段落。

(2)配置應用擴展

Snip20160808_165.png

點擊ON后骨望,系統(tǒng)會彈出提示框硬爆,讓你選擇證書,因為共享域是在證書的基礎上配置的擎鸠。證書選擇后缀磕,會把對應的所有共享域顯示在App Groups中。

Snip20160808_168.png
Snip20160808_170.png

選中我們之前在宿主應用創(chuàng)建(選擇)的共享域。

OK袜蚕,應用擴展的共享域配置完畢糟把。

2、數(shù)據(jù)共享
(1)NSUserDefaults

NSUserDefaults *userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.testAppExtension"];
獲取共享域的偏好設置

接下來平時怎么用這里就怎么用牲剃。
(2)數(shù)據(jù)庫
在創(chuàng)建應用擴展前遣疯,數(shù)據(jù)庫我是放到這個路徑下的。

[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"TestDB.sqlite"]

而現(xiàn)在颠黎,即使共享域配置完畢另锋,應用擴展繼續(xù)訪問這個路徑下的數(shù)據(jù)庫也是訪問不到的,因為共享域它有自己的路徑。宿主應用和應用擴展之間的空間關系如下:

Snip20160808_172.png

所以耸携,我們要將數(shù)據(jù)庫放在共享域的路徑下雏婶。共享域的路徑如下:

[[[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.testAppExtension"] absoluteString] stringByAppendingPathComponent:@"TestDB.sqlite"]

通過containerURLForSecurityApplicationGroupIdentifier方法和共享域標識符我們可以獲取到該共享域的路徑

OK,共享數(shù)據(jù)到這里暫告一段落室梅。

3、應用擴展開始編碼


Snip20160808_173.png

前面說了這里可以隨便改疚宇,修改后的結(jié)構(gòu)如下:

Snip20160808_174.png

這里別忘了把新的storyboard和控制器關聯(lián)一下亡鼠。

然后我們來看ActionViewController.m文件。


Snip20160808_176.png

target選擇PassowrdAppExtension進行調(diào)試敷待。

然后選擇在哪個host app中進行測試间涵。


Snip20160808_178.png

點擊RUN,報錯榜揖。

Paste_Image.png

通過錯誤信息可以知道是文件引用錯誤勾哩。

這是因為此時應用擴展還不能隨便使用項目內(nèi)的其他文件。因為到目前為止举哟,都是宿主應用的target在引用這些文件思劳。

看到這個錯誤我的第一反應是把Password和PasswordDBTool的類文件加入到應用擴展 target 的編譯文件中去,這樣在擴展中自然也就可以使用了妨猩。但是潜叛,文件數(shù)量少,這樣做還可以壶硅。如果文件數(shù)量大威兜,再這樣做會十分麻煩,出錯的概率會大大增加庐椒,效率也十分低下牡属,所有類弄的團團糟維護起來也很麻煩。所幸我們可以創(chuàng)建一個Framework文件扼睬,讓Framework文件引用這些需要共享的類逮栅,再讓宿主應用和應用擴展分別導入Framework文件悴势。這樣做就很好的解決了問題,還不容易出錯措伐,也便于后期維護特纤。

一步一步來實現(xiàn)剛才說的。

1侥加、創(chuàng)建framework文件

Snip20160808_181.png
Snip20160808_182.png

framework文件的命名規(guī)范一些捧存,以Kit為結(jié)尾。

Snip20160808_183.png

創(chuàng)建完framework后工程目錄如下

Snip20160808_184.png

2担败、引用文件
(1)先把宿主應用target的文件引用刪除昔穴,因為應用擴展同樣要使用FMDB,所以也要把第三方文件從target中刪除提前,否則編譯照樣會報錯吗货。

Snip20160808_185.png

點擊Compile Sources下面的-號把標注的類全部刪除。

Snip20160808_186.png

最后只剩下3個文件狈网。

(2)增加AppExtensionKit的引用文件

Snip20160808_187.png

點+號把剛才刪除的類加進來宙搬。添加完后如下:

Snip20160808_188.png

需要注意的是,在這里不要添加xib文件拓哺,xib在哪修改下面會說勇垛。

(3)為應用擴展導入AppExtensionKit文件

Snip20160808_189.png
Snip20160808_190.png

添加完后編譯一下,報錯士鸥,40多個闲孤。
這是因為應用擴展也要用到libsqlite3.0.tbd這個包,但是并沒有為應用擴展添加這個包烤礁,所以讼积,重復上面的操作,把libsqlite3.0.tbd加入到AppExtensionKit中鸽凶。

Snip20160808_191.png
Snip20160808_192.png

再編譯一下币砂,錯誤全部消失不見建峭。OK玻侥,配置全部完成。

(4)豐富一下ActionViewController.m的代碼亿蒸,把共享區(qū)數(shù)據(jù)庫的數(shù)據(jù)全部打印出來凑兰。

Paste_Image.png

編譯無錯,運行崩潰边锁。崩潰位置是第40行姑食。
原因:PasswrodCell是從xib加載的,但我們并沒有把xib文件加入到AppExtensionKit中茅坛。知道問題出在哪了音半,去解決则拷。

在宿主應用的target中,找到PasswordCell的引用并刪除曹鸠。如下:

Paste_Image.png

在targets中選中AppExtesnionKit煌茬,為其添加Password.xib的引用,如下:

Paste_Image.png

操作完后彻桃,xib文件從原來bundle下的路徑變成了bundle下AppExtensionKit下的路徑坛善。

做完這些還不夠,我們還要在ExtensionDemo和PasswordAppExtension兩個target下的Copy Bundle Resources中將AppExtensionKit導入進來邻眷,否則宿主應用和應用擴展還是用不了PasswordCell.xib眠屎。如圖:

ExtensionDemo的target:

Paste_Image.png

PasswordAppExtension的target:

Paste_Image.png

那我們再次加載Password.xib文件,就需要從Bundle下的AppExtensionKit文件中加載肆饶。
加載方式代碼如下:

cell = [[NSBundle mainBundle] loadNibNamed:@"AppExtensionKit.framework/ExtensionCell" owner:nil options:nil].lastObject;
Paste_Image.png

運行項目改衩,效果如圖:

2.pic.jpg

和宿主應用顯示的數(shù)據(jù)一模一樣。

自此抖拴,宿主應用與應用擴展的數(shù)據(jù)共享就完成了燎字。

接下來,是Host App和應用擴展之間的數(shù)據(jù)傳遞阿宅。

Host App

Host App界面實現(xiàn)和代碼邏輯都比較簡單候衍。

實現(xiàn)效果如下:

11111.gif

代碼部分:
點擊按鈕時會觸發(fā)如下代碼:

Paste_Image.png
Paste_Image.png

這里有幾個關鍵點:
(1)首先,我創(chuàng)建了一個字典并且保存了兩個參數(shù)洒放,一個是版本號蛉鹿,一個是URLKey(我要將這個參數(shù)傳遞給應用擴展,應用擴展會用這個key做為查詢條件到數(shù)據(jù)庫中查詢數(shù)據(jù)往湿,然后將查詢到的數(shù)據(jù)再回傳給host app)妖异。

(2)我把這個字典賦值給了NSItemProvider的item屬性,又將NSItemProvider對象添加到了NSExtensionItem對象的attachments數(shù)組中领追。在應用擴展中他膳,我們也按照這種方式來逐步獲取字典。

(3)前面說過绒窑,系統(tǒng)提供了KUTTypeImage等字段用來在應用擴展中獲取來自host app傳遞過來的值棕孙,而這個字段我們是可以自定義的。如圖些膨,這個自定義字段也是通過NSItemProvider對象來傳遞的蟀俊。

Paste_Image.png

(3)在應用擴展中,我們?nèi)绾瓮ㄟ^這個自定義字段來獲取host app傳遞過來的數(shù)據(jù)订雾。如圖:

Paste_Image.png

關鍵代碼已經(jīng)用紅色方框標注出來了肢预。

也就是說通過這句代碼我們可以獲取到host app向應用傳遞的typeIdentifier。這兩個地方要一致才能獲取到host app傳遞過來的數(shù)據(jù)洼哎。

在block回調(diào)中把host app傳遞過來的數(shù)據(jù)取出來烫映,然后到數(shù)據(jù)庫中進行查詢就可以了沼本。

(4)數(shù)據(jù)查詢到了怎么回傳給host app呢?
剛才已經(jīng)展示過了應用擴展的界面锭沟,應用擴展實現(xiàn)了與宿主應用的數(shù)據(jù)共享擅威。如圖:


2.pic.jpg

當點擊右上角關閉按鈕時,什么數(shù)據(jù)都不回傳冈钦。
當點擊某個cell時郊丛,把對應的數(shù)據(jù)(也就是某條密碼)回傳給Host App,并把該密碼的賬戶和密碼顯示在對應的輸入框中瞧筛。

代碼如下:
關閉按鈕的點擊事件:

Paste_Image.png

單元格點擊事件:

Paste_Image.png

到這里厉熟,應用擴展對host app的數(shù)據(jù)回傳就搞定了。

(5)host app拿到回傳數(shù)據(jù)進行登錄

Paste_Image.png

這一步是通過UIActivityViewController對象的回調(diào)完成的较幌。

不管是把數(shù)據(jù)從host app傳給應用擴展揍瑟,
還是把數(shù)據(jù)從應用擴展傳給host app,
數(shù)據(jù)的傳遞依靠的都是NSExtensionItem和NSItemProvider乍炉,
如果非要給他們弄一個關系便于理解的話绢片,大概是這樣的:
存:
需要傳遞的數(shù)據(jù) -> NSItemProvider -> NSExtensionItem -> NSExtensionContext
取:
NSExtensionContext -> NSExtensionItem -> NSItemProvider -> 拿到需要傳遞的數(shù)據(jù)
一層一層的包裹著岛琼。

OK底循,全部搞定。

我們來看一下最終的效果槐瑞。

fdfas.gif

額熙涤,還差一點。

沒有給我們的應用擴展配置一個圖標困檩。

Snip20160808_212.png
Snip20160808_214.png
Snip20160808_215.png

OK祠挫,全部搞定。

需求實現(xiàn)了悼沿。

但是在使用擴展的過程中還是有不少的坑等舔,為了謹慎起見,在擴展中編寫代碼調(diào)用方法糟趾,多看看文檔慌植。有很多方法都有官方注釋,有些方法是不能在應用擴展中使用的拉讯。

好涤浇,今天就到這里鳖藕。

其他應用擴展資料傳送門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末魔慷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子著恩,更是在濱河造成了極大的恐慌院尔,老刑警劉巖蜻展,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異邀摆,居然都是意外死亡纵顾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門栋盹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來施逾,“玉大人,你說我怎么就攤上這事例获『憾睿” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵榨汤,是天一觀的道長蠕搜。 經(jīng)常有香客問我,道長收壕,這世上最難降的妖魔是什么妓灌? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮蜜宪,結(jié)果婚禮上虫埂,老公的妹妹穿的比我還像新娘。我一直安慰自己圃验,他們只是感情好告丢,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著损谦,像睡著了一般岖免。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上照捡,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天颅湘,我揣著相機與錄音,去河邊找鬼栗精。 笑死闯参,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的悲立。 我是一名探鬼主播鹿寨,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼薪夕!你這毒婦竟也來了脚草?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤原献,失蹤者是張志新(化名)和其女友劉穎馏慨,沒想到半個月后埂淮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡写隶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年倔撞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慕趴。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡痪蝇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冕房,到底是詐尸還是另有隱情霹俺,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布毒费,位于F島的核電站丙唧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏觅玻。R本人自食惡果不足惜想际,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望溪厘。 院中可真熱鬧胡本,春花似錦、人聲如沸畸悬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蹋宦。三九已至披粟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冷冗,已是汗流浹背守屉。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蒿辙,地道東北人拇泛。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像思灌,于是被迫代替她去往敵國和親俺叭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容