iOS的Share Extension直接分享视频到微信

iOS11开始不能通过SLComposeViewController直接分享到微信了,只能通过UIActivityViewController一步一步来,分享步骤比较繁琐。已经放弃。
——2017年11月1日

iOS app分享内容到微信有两种方式:

1 集成微信官方SDK,跳转到微信分享(参看简书app分享)
2 利用iOS Social.framework直接在自己的app内部实现分享(参看系统相册的分享)

集成微信官方SDK,跳转到微信分享 ![Uploading share3_795019.gif . . .]
利用iOS Social.framework直接在自己的app内部实现分享

Social.framework直接在自己的app内部实现分享图片

项目第一版要求直接分享多张图片到朋友圈,第一种分享方式是不支持的,通过系统相册分享发现可以选中多张照片分享给朋友或者朋友圈。
代码:

    UIImage *imageToShareOne = [UIImage imageNamed:@"狮子"];
    UIImage *imageToShareTwo = [UIImage imageNamed:@"老虎"];
    
    NSArray *activityItems = @[imageToShareOne, imageToShareTwo];
    
    UIActivityViewController *activityVC = [[UIActivityViewController alloc]initWithActivityItems:activityItems
                                            
                                                                            applicationActivities:nil];
    
    //不出现在活动项目
    activityVC.excludedActivityTypes = @[UIActivityTypePrint, UIActivityTypeCopyToPasteboard,
                                         
                                         UIActivityTypeAssignToContact,UIActivityTypeSaveToCameraRoll];
    
    // 3.弹出分享控制器(以Modal形式弹出)
    UIViewController * rootVc = [UIApplication sharedApplication].keyWindow.rootViewController;
    [rootVc presentViewController:activityVC animated:TRUE completion:nil];
UIActivityViewController分享到微信.gif

产品大大看后说能不能简化一下,现在让用户分享到微信需要操作太多步骤,省掉第一步选择微信直接出现分享界面。

通过SLComposeViewController好像可以实现直接分享,composeViewControllerForServiceType方法传递一个需要分享的app对应的serviceType,然后返回一个SLComposeViewController对象,然后present这个对象就可以.
但是系统api只给了这么几个app的字符串:Twitter ,Facebook ,SinaWeibo ,TencentWeibo,LinkedIn 我想直接分享到微信该怎么办?

SOCIAL_EXTERN NSString *const SLServiceTypeTwitter NS_AVAILABLE(10_8, 6_0);
SOCIAL_EXTERN NSString *const SLServiceTypeFacebook NS_AVAILABLE(10_8, 6_0);
SOCIAL_EXTERN NSString *const SLServiceTypeSinaWeibo NS_AVAILABLE(10_8, 6_0);
SOCIAL_EXTERN NSString *const SLServiceTypeTencentWeibo NS_AVAILABLE(10_9, 7_0);
SOCIAL_EXTERN NSString *const SLServiceTypeLinkedIn NS_AVAILABLE(10_9, NA);

感谢大神解救了我:程序内分享到微信
iOS8之后系统推出的Share Extension,微信App的Share Extension往系统里注册了分享到微信需要的serviceType为:"com.tencent.xin.sharetimeline"
做法如下,代码:

    NSString *test = @"com.tencent.xin.sharetimeline";
    if (![SLComposeViewController isAvailableForServiceType:test]) {
        NSLog(@"或者没有配置相关的帐号");
        return;
    }
    
    // 2.创建分享的控制器
    SLComposeViewController *composeVc = [SLComposeViewController composeViewControllerForServiceType:test];
    if (composeVc == nil){
        NSLog(@"没有安装微信");
        return;
    }
    // 2添加图片
    [composeVc addImage:[UIImage imageNamed:@"狮子"]];
    [composeVc addImage:[UIImage imageNamed:@"老虎"]];
    
    // 3.弹出分享控制器(以Modal形式弹出)
    UIViewController * rootVc = [UIApplication sharedApplication].keyWindow.rootViewController;
    [rootVc presentViewController:composeVc animated:TRUE completion:nil];
    
    // 4.监听用户点击了取消还是发送
    /*
     SLComposeViewControllerResultCancelled,
     SLComposeViewControllerResultDone
     */
    composeVc.completionHandler = ^(SLComposeViewControllerResult result){
        if (result == SLComposeViewControllerResultCancelled) {
            NSLog(@"点击了取消");
        } else {
            NSLog(@"点击了发送");
        }
    };
SLComposeViewController分享

那是不是qq也实现了Share Extension,并且往系统注册了自己的serviceType,以及其他的app有没有呢?

程序内分享到微信这篇文章告诉我们,只需调用下面一句代码。

  SLComposeViewController *composeVc = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeSinaWeibo];

下面看看控制台输出,手机内所有可用的Share Extension的bundle Id 都出来了

2017-06-07 17:39:32.529838 ShareVedioWechat[56472:7845914] [core] SLComposeViewController _shareExtensionWithIdentifier: continuous discovery block got extensions (
    "<NSExtension: 0x1703612c0> {id = com.apple.reminders.RemindersEditorExtension}",
    "<NSExtension: 0x17017fe00> {id = com.apple.Health.HealthShareExtension}",
    "<NSExtension: 0x170360000> {id = com.apple.mobileslideshow.StreamShareService}",
    "<NSExtension: 0x170360180> {id = com.apple.Music.MediaSocialShareService}",
    "<NSExtension: 0x170360300> {id = com.apple.share.SinaWeibo.post}",
    "<NSExtension: 0x170360480> {id = com.apple.share.Twitter.post}",
    "<NSExtension: 0x170360600> {id = com.apple.share.Flickr.post}",
    "<NSExtension: 0x170360780> {id = com.tencent.mqq.ShareExtension}",
    "<NSExtension: 0x170360900> {id = com.apple.share.Vimeo.post}",
    "<NSExtension: 0x170360a80> {id = com.apple.mobilenotes.SharingExtension}",
    "<NSExtension: 0x170360c00> {id = com.apple.share.TencentWeibo.post}",
    "<NSExtension: 0x170360d80> {id = com.apple.share.Facebook.post}",
    "<NSExtension: 0x17017fc80> {id = com.sina.weibo.ShareExtension}",
    "<NSExtension: 0x170360fc0> {id = com.tencent.xin.sharetimeline}",
    "<NSExtension: 0x170361140> {id = com.jianshu.Hugo.Share-Extension}"
) error (null)
2017-06-07 17:39:32.531016 ShareVedioWechat[56472:7845914] [core] SLComposeViewController _shareExtensionWithIdentifier: continuous discovery block did update _identifierToShareExtensionMap {
    "com.apple.Health.HealthShareExtension" = "<NSExtension: 0x17017fe00> {id = com.apple.Health.HealthShareExtension}";
    "com.apple.Music.MediaSocialShareService" = "<NSExtension: 0x170360180> {id = com.apple.Music.MediaSocialShareService}";
    "com.apple.mobilenotes.SharingExtension" = "<NSExtension: 0x170360a80> {id = com.apple.mobilenotes.SharingExtension}";
    "com.apple.mobileslideshow.StreamShareService" = "<NSExtension: 0x170360000> {id = com.apple.mobileslideshow.StreamShareService}";
    "com.apple.reminders.RemindersEditorExtension" = "<NSExtension: 0x1703612c0> {id = com.apple.reminders.RemindersEditorExtension}";
    "com.apple.share.Facebook.post" = "<NSExtension: 0x170360d80> {id = com.apple.share.Facebook.post}";
    "com.apple.share.Flickr.post" = "<NSExtension: 0x170360600> {id = com.apple.share.Flickr.post}";
    "com.apple.share.SinaWeibo.post" = "<NSExtension: 0x170360300> {id = com.apple.share.SinaWeibo.post}";
    "com.apple.share.TencentWeibo.post" = "<NSExtension: 0x170360c00> {id = com.apple.share.TencentWeibo.post}";
    "com.apple.share.Twitter.post" = "<NSExtension: 0x170360480> {id = com.apple.share.Twitter.post}";
    "com.apple.share.Vimeo.post" = "<NSExtension: 0x170360900> {id = com.apple.share.Vimeo.post}";
    "com.jianshu.Hugo.Share-Extension" = "<NSExtension: 0x170361140> {id = com.jianshu.Hugo.Share-Extension}";
    "com.sina.weibo.ShareExtension" = "<NSExtension: 0x17017fc80> {id = com.sina.weibo.ShareExtension}";
    "com.tencent.mqq.ShareExtension" = "<NSExtension: 0x170360780> {id = com.tencent.mqq.ShareExtension}";
    "com.tencent.xin.sharetimeline" = "<NSExtension: 0x170360fc0> {id = com.tencent.xin.sharetimeline}";
}

SLComposeViewController能调用所有Share Extension。实现直接分享
至此完美解决,之后项目完成发版

Social.framework直接在自己的app内部实现分享视频

项目发版之后马不停蹄开始下一版本的迭代,产品说分享图片很好,但是我们要做的更diao,为了让用户更加直观的了解我们的产品,我们要分享视频!像图片一样直接分享,略过选择微信这一步*&¥##¥%#……&……%……%
我。。。。。。这要命。
看一下SLComposeViewController的头文件里暴露的接口:

屏幕快照 2017-06-07 下午3.43.50.png

有关设置分享内容的方法就这么几个,vedio往哪里放???

通过操作发现,系统相册可以选择视频分享到微信的,并且弹出的应该也是SLComposeViewController

一步一步的来,先实现和系统一样的分享视频功能,
第一步:先把视频下载到沙盒中(我用的AFN下载)
第二步:把视频保存到相册中,拿到在相册中的地址url(这步是必须的,我尝试直接通过视频在沙盒中的地址url分享,每次都发送不成功)
第三步:分享

  • 其中前两步是基础工作,必须先将视频保存到相册拿到相册中的url,通过把url传给SLComposeViewController或者UIActivityViewController来实现视频的分享(为什么不能把视频转为NSData传递data或者干脆直接用沙盒中视频的url分享之类的问题,我暂时也回答不了,这些算是我趟过坑之后经验之谈,虽然知其然更要知其所以然,但是好多东西苹果爸爸都在藏着掖着,语焉不详的文档,我暂时还没有空深挖,只能出个基本教程)

下载代码,url为视频下载地址,filePathUrl为存到沙盒中的位置,fileName为存到沙盒中的名称(ViewController.m文件中):

#pragma mark - 下载视频
- (void)downloadVideoWithUrl:(NSString *)url filePath:(NSURL *)filePathUrl fileName:(NSString *)fileName {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
    NSURLSessionDownloadTask *task = [manager downloadTaskWithRequest:request progress:^(NSProgress *downloadProgress){
        NSLog(@"%@",downloadProgress);
    } destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
        return filePathUrl;
    } completionHandler:^(NSURLResponse *response, NSURL *filePathUrl, NSError *error) {
        // 从沙盒保存到相册
        [CLVedioDownloadManager save:filePathUrl fileName:fileName];
    }];
    [task resume];
}

把视频保存到沙盒,url为视频在沙盒中位置,fileName为视频名称(CLVedioDownloadManager.m文件中):

+ (void)save:(NSURL*)url fileName:(NSString *)fileName{
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library writeVideoAtPathToSavedPhotosAlbum:url
                                completionBlock:^(NSURL *assetURL, NSError *error) {
                                    if (error) {
                                        NSLog(@"保存视频到相册失败:%@",error);
                                    } else {
                                        NSLog(@"保存视频到相册成功:%@",assetURL);
                                        [CLVedioShareManager directShareVedio:assetURL];
                                    }
                                }];
}

现在去相册看看就可以看到保存下来的视频了,基础工作完成,
利用UIActivityViewController实现和相册一样的分享效果,其中url为视频在相册中的地址,只需要传递一个url就可以分享视频了:

+ (void)indirectShareVedio:(NSURL *)url {
    NSArray *activityItems = @[url];
    
    UIActivityViewController *activityVC = [[UIActivityViewController alloc]initWithActivityItems:activityItems
                                                                            applicationActivities:nil];
    //不出现在活动项目
    activityVC.excludedActivityTypes = @[UIActivityTypePrint, UIActivityTypeCopyToPasteboard,UIActivityTypeAssignToContact,UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList];
    
    //给activityVC的属性completionHandler写一个block。
    //用以UIActivityViewController执行结束后,被调用,做一些后续处理。
    UIActivityViewControllerCompletionWithItemsHandler myBlock = ^(UIActivityType activityType, BOOL completed, NSArray * returnedItems, NSError * activityError)
    {
        
        if (completed)
        {
            
        }
        else
        {
            
        }
    };
    
    // 初始化completionHandler,当post结束之后(无论是done还是cancell)该blog都会被调用
    activityVC.completionWithItemsHandler = myBlock;
    
    UIViewController * rootVc = [UIApplication sharedApplication].keyWindow.rootViewController;
    [rootVc presentViewController:activityVC animated:TRUE completion:nil];
}
gif截图时长有限可以分享成功.gif

下面要考虑的是如何省略掉UIActivityViewController直接通过SLComposeViewController分享,省略了选择微信的那一步。踩坑过程省略,直接说流程:
前提:这个项目不通过appStore分发下载,走企业账号,所以在我找不到合适的方法的时候,我用了私有方法。这样不会存在不过审核这一说
SLComposeViewController的addImage,addURL这些方法最终都是在内部转化为NSExtensionItem对象,然后SLComposeViewController调用私有方法addExtensionItem实现分享内容的加载。
思路:
自己用视频在相册中的地址url构造一个符合条件的NSExtensionItem的对象,然后对SLComposeViewController对象执行addExtensionItem方法,参数就是自己构造的NSExtensionItem对象

代码

+ (void)directShareVedio:(NSURL *)url {
    NSString *test = @"com.tencent.xin.sharetimeline";
    if (![SLComposeViewController isAvailableForServiceType:test]) {
        NSLog(@"或者没有配置相关的帐号");
        return;
    }
    
    // 2.创建分享的控制器
    SLComposeViewController *composeVc = [SLComposeViewController composeViewControllerForServiceType:test];
    if (composeVc == nil){
        NSLog(@"没有安装微信");
        return;
    }
    // 重点
    [composeVc addVideoURL:url];
    
    // 3.弹出分享控制器(以Modal形式弹出)
    UIViewController * rootVc = [UIApplication sharedApplication].keyWindow.rootViewController;
    [rootVc presentViewController:composeVc animated:TRUE completion:nil];
    
    
    // 4.监听用户点击了取消还是发送
    /*
     SLComposeViewControllerResultCancelled,
     SLComposeViewControllerResultDone
     */
    composeVc.completionHandler = ^(SLComposeViewControllerResult result){
        if (result == SLComposeViewControllerResultCancelled) {
            NSLog(@"点击了取消");
        } else {
            NSLog(@"点击了发送");
        }
    };
}

(创建SLComposeViewController的category,构造NSExtensionItem之后用self performSelector调用addExtensionItem):

#import "SLComposeViewController+Method.h"
#import <MobileCoreServices/MobileCoreServices.h>

@implementation SLComposeViewController (Method)

- (BOOL)addVideoURL:(NSURL *)url {
    NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithItem:url typeIdentifier:(NSString *)kUTTypeQuickTimeMovie];    
    NSExtensionItem *extensionItem = [NSExtensionItem new];
    extensionItem.attachments = [NSArray arrayWithObject:itemProvider];
    
    return [self performSelector:@selector(addExtensionItem:) withObject:extensionItem];
}

@end
分享视频省略选择微信的步骤

至此完美完成需求

demo地址:https://github.com/thinkq/ShareVedioWechat

参考:程序内分享到微信

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一种新的协议。它实...
    香橙柚子阅读 23,554评论 8 183
  • 今年的春天来的晚,人间四月芳菲始呀~~ 麦子该没过脚脖子,放风筝的时节就到了。风筝是消耗品,还没上几次天就...
    杨舒绿阅读 260评论 0 0
  • 如果我们下一次见面会是什么样子?那一定是久别重逢吧……我们之间就像是车窗外飞驰而过的风景当你回头再看一眼时却发现她...
    滕龙振华阅读 668评论 0 10
  • 2009年,那年我,19;她,22… 夏天,毒火般的太阳烘烤着大地… 认识她是个偶然的机会。高考失利我回到家乡复读...
    狼郎阅读 191评论 0 1