使用系統(tǒng)分享髓梅。將Safari中的網(wǎng)頁(yè)分享給微信中的好友寡喝。
0.gif
1.新建ShareExtension拯田。
2.配置Share Extension圆仔,允許發(fā)送的數(shù)據(jù)類(lèi)型垃瞧,url,image,mp3,mp4,pdf,word,excel,ppt。
7.png
3.處理Share Extension中的數(shù)據(jù)荧缘。
Share Extension中默認(rèn)都會(huì)有一個(gè)數(shù)據(jù)展現(xiàn)的UI界面皆警。該界面繼承SLComposeServiceViewController這個(gè)類(lèi)型,如:
@interface ShareViewController : SLComposeServiceViewController
@end
一般采用自定義控制器:
@interface ShareViewController : SLComposeServiceViewController
@end
4.從inputItems中獲取數(shù)據(jù)截粗。
[self.extensionContext.inputItems enumerateObjectsUsingBlock:^(NSExtensionItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (obj.attributedContentText.string.length > 0)
{
self.contentText = obj.attributedContentText.string;
}
[obj.attachments enumerateObjectsUsingBlock:^(NSItemProvider * _Nonnull itemProvider, NSUInteger idx, BOOL * _Nonnull stop) {
if ([itemProvider hasItemConformingToTypeIdentifier:@"public.url"])
{
[itemProvider loadItemForTypeIdentifier:@"public.url" options:nil completionHandler:^(id<NSSecureCoding> _Nullable item, NSError * _Null_unspecified error) {
if ([(NSObject *)item isKindOfClass:[NSURL class]])
{
self.url = (NSURL *)item;
NSInteger preValue = self.flag.integerValue;
if ([self.url isFileURL])
{
self.flag = [NSNumber numberWithInteger:(preValue|url_file)];
}
else
{
self.flag = [NSNumber numberWithInteger:(preValue|url_flag)];
}
}
[self refreshView];
}];
}
if ([itemProvider hasItemConformingToTypeIdentifier:@"public.image"])
{
[itemProvider loadItemForTypeIdentifier:@"public.image" options:nil completionHandler:^(id item, NSError *error) {
if ([item isKindOfClass:[NSURL class]])
{
[self.arrImagePath addObject:item];
NSInteger preValue = self.flag.integerValue;
self.flag = [NSNumber numberWithInteger:(preValue | url_image)];
[self refreshView];
count ++;
}
else if ([item isKindOfClass:[UIImage class]] && !self.thumb)
{
self.thumb = (UIImage *)item;
NSInteger preValue = self.flag.integerValue;
self.flag = [NSNumber numberWithInteger:(preValue | url_image)];
[self refreshView];
count ++;
}
}];
}
if ([itemProvider hasItemConformingToTypeIdentifier:(__bridge NSString *)kUTTypeText])
{
NSInteger preValue = self.flag.integerValue;
self.flag = [NSNumber numberWithInteger:(preValue|url_text)];
[itemProvider loadItemForTypeIdentifier:(__bridge NSString *)kUTTypeText options:nil completionHandler:^(id item, NSError *error) {
if ([item isKindOfClass:[NSString class]])
{
NSString *str = (NSString *)item;
if ([str containsString:@"http://"] || [str containsString:@"https://"] || [str containsString:@"file:///"])
{
if (!self.url)
{
self.url = [NSURL URLWithString:str];
if ([self.url isFileURL])
{
self.flag = [NSNumber numberWithInteger:(preValue|url_file)];
}
else
{
self.flag = [NSNumber numberWithInteger:(preValue|url_flag)];
}
}
}
else
{
[self.text appendString:str];
[self.text appendString:@"\n"];
}
}
[self refreshView];
}];
}
if ([itemProvider hasItemConformingToTypeIdentifier:@"public.movie"])
{
[itemProvider loadItemForTypeIdentifier:@"public.movie" options:nil completionHandler:^(id<NSSecureCoding> _Nullable item, NSError * _Null_unspecified error)
{
NSInteger preValue = self.flag.integerValue;
NSURL *fileurl = (NSURL *)item;
if ([fileurl isFileURL])
{
self.flag = [NSNumber numberWithInteger:(preValue | url_file)];
self.url = fileurl;
[self refreshView];
}
}];
}
}];
}];
上面的例子中遍歷了extensionContext的inputItems數(shù)組中所有NSExtensionItem對(duì)象信姓,然后從這些對(duì)象中遍歷attachments數(shù)組中的所有NSItemProvider對(duì)象。匹配第一個(gè)包含public.url標(biāo)識(shí)的附件(具體要匹配什么資源绸罗,數(shù)量是多少皆有自己的業(yè)務(wù)所決定)意推。注意:[self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];這行代碼,主要是使到視圖控制器不被關(guān)閉珊蟀,等到實(shí)現(xiàn)相應(yīng)的處理后再進(jìn)行調(diào)用該方法菊值,對(duì)分享視圖進(jìn)行關(guān)閉外驱。調(diào)用該方法則回到宿主App。
5.傳遞Share Extension中的數(shù)據(jù)腻窒。有個(gè)App Groups功能可以據(jù)此傳遞數(shù)據(jù)昵宇。
WX20190210-223758.png
WX20190210-224011.png
1.依據(jù)寫(xiě)文件傳遞數(shù)據(jù)。例如:要分享的App儲(chǔ)存登錄信息儿子。
//獲取分組的共享目錄
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.cn.com.mengniu.oa.sharextension"];
NSURL *fileURL = [groupURL URLByAppendingPathComponent:@"login.txt"];
if (success) {
[@"isLogin" writeToURL:fileURL atomically:YES encoding:NSUTF8StringEncoding error:nil];
} else {
[@"isNotLogin" writeToURL:fileURL atomically:YES encoding:NSUTF8StringEncoding error:Nil];
}
//獲取儲(chǔ)存在App Groups中的登錄信息瓦哎。
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.cn.com.mengniu.oa.sharextension"];
NSURL *fileURL = [groupURL URLByAppendingPathComponent:@"login.txt"];
NSString *isLoginStatus = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:nil];
2.依據(jù)NSUserDefaults,儲(chǔ)存數(shù)據(jù),試了幾次沒(méi)有取成功過(guò)柔逼。
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.xxx.sharextension"];
if (![userDefaults objectForKey:@"isLogin"])
{
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"溫馨提示"
message:@"請(qǐng)登錄"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"確定"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
UIResponder* responder = self;
while ((responder = [responder nextResponder]) != nil)
{
if([responder respondsToSelector:@selector(openURL:)] == YES)
{
[responder performSelector:@selector(openURL:) withObject:[NSURL URLWithString:@"sharefile://"]];
}
}
}];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"取消"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {}];
[alert addAction:cancelAction];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
會(huì)報(bào)錯(cuò):
[User Defaults] Couldn't read values in CFPrefsPlistSource<0x1c010e340> (Domain:
group.cn.com.mengniu.oa.sharextension, User: kCFPreferencesAnyUser, ByHost:
Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers,
detaching from cfprefsd
網(wǎng)上說(shuō)在儲(chǔ)存App Groups時(shí)要添加Team ID蒋譬。之后取值時(shí)雖然不會(huì)再報(bào)錯(cuò),但取出來(lái)的值為nil愉适。
6.其實(shí)蘋(píng)果官方除了Today Extension外犯助,其他Extension是不提供跳轉(zhuǎn)接口的。所以這里總結(jié)的是兩種非正常的方式维咸。
1.在Share Extension中無(wú)法獲取到UIApplication對(duì)象剂买,則通過(guò)拼接字符串獲取。
NSURL *destinationURL = [NSURL URLWithString:[NSString stringWithFormat:@"sharefile://%@",saveFilePath]];
// Get "UIApplication" class name through ASCII Character codes.
NSString *className = [[NSString alloc] initWithData:[NSData dataWithBytes:(unsigned char []){0x55, 0x49, 0x41, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E} length:13] encoding:NSASCIIStringEncoding];
if (NSClassFromString(className)) {
id object = [NSClassFromString(className) performSelector:@selector(sharedApplication)];
[object performSelector:@selector(openURL:) withObject:destinationURL];
}
2.這種方式主要實(shí)現(xiàn)原理是通過(guò)響應(yīng)鏈找到Host App的UIApplication對(duì)象腰湾,通過(guò)該對(duì)象調(diào)用openURL方法返回自己的應(yīng)用雷恃。
UIResponder *responder = self;
while ((responder = [responder nextResponder]) != nil) {
if ([responder respondsToSelector:@selector(openURL:)] == YES) {
[responder performSelector:@selector(openURL:) withObject:[NSURL URLWithString:@"sharefile://"]];
}
}
7.未登錄的處理。登錄成功后先寫(xiě)文件儲(chǔ)存登錄信息到App Groups中费坊,退出登錄后倒槐,刪除儲(chǔ)存在App Groups中的登錄信息。到ShareViewController中先判斷是否登錄附井,若未登錄讨越,則彈窗提示登錄不再?gòu)椘鸢l(fā)送框。
1.登錄成功永毅,則保存登錄信息把跨。
//獲取分組的共享目錄
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.cn.com.mengniu.oa.sharextension"];
NSURL *fileURL = [groupURL URLByAppendingPathComponent:@"login.txt"];
if (success) {
[@"isLogin" writeToURL:fileURL atomically:YES encoding:NSUTF8StringEncoding error:nil];
} else {
[@"isNotLogin" writeToURL:fileURL atomically:YES encoding:NSUTF8StringEncoding error:Nil];
}
});
2.退出登錄或未登錄,則清空已經(jīng)保存的登錄信息沼死。
//獲取分組的共享目錄
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.cn.com.mengniu.oa.sharextension"];
NSURL *fileURL = [groupURL URLByAppendingPathComponent:@"login.txt"];
[@"isNotLogin" writeToURL:fileURL atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.cn.com.mengniu.oa.sharextension"];
NSURL *fileURL = [groupURL URLByAppendingPathComponent:@"login.txt"];
NSString *isLoginStatus = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:nil];
//如果未登錄提示登錄
if (isLoginStatus && [isLoginStatus isEqualToString:@"isNotLogin"]) {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"請(qǐng)先登錄辦隨着逐,再分享"
message:nil
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"確定"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
UIResponder* responder = self;
while ((responder = [responder nextResponder]) != nil)
{
if([responder respondsToSelector:@selector(openURL:)] == YES)
{
[responder performSelector:@selector(openURL:) withObject:[NSURL URLWithString:@"sharefile://"]];
}
[self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
}
}];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"取消"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
[self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
}];
[alert addAction:cancelAction];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
else//已登錄加載發(fā)送框
{
[self.view addSubview:container];
}
8.在ShareExtension中處理邏輯代碼。