最近,再开发一个视频分享的小功能,经过一天的折腾,终于搞定了,这里记录一下,供大家参考,如果有更好的方法,请发邮件asdemon235b@126.com

需求:将程序生成的视频分享到Facebook和Instagram。

目前情况:已经实现了分享图片到Facebook和Instagram。

走的弯路:首先,Instagram对于视频的时长有要求,经测试,目前是3.0s,这就对生成的视频有了新的限制,如果小于这个长度,需要再次循环播放一遍。其次,开始时以为分享图片和视频的实现方式是一样的,后来发现完全不同,浪费了点时间。最后,Facebook和Instagram的视频分享不像图片那样,文件在程序的沙盒内即可,视频必须在系统的Photo App中才能分享,URL必须是aaset url,要知道苹果已经用Photo Framework代替AssetsLibrary了,此处省略三千字。。。 。

Facebook分享

图片分享

NSData *sharedImageData;
//得到分享数据的data
if ([[self imageMIME] isEqualToString:@"image/gif"]) {
        HSKeyboardGIFImage *gifImage = [self gifImage];
        if (gifImage.frameCount > 0) {
                UIImage *image =  [gifImage imageAtIndex:gifImage.frameCount > 1 ? 1 : 0];
                sharedImageData = UIImagePNGRepresentation(image);
        } else {
                self.block(ShareResultStateFailed);
                return NO;
        }
} else {
        sharedImageData = [self emojiData];
}
//使用FB SDK分享
FBSDKSharePhoto *photo = [[FBSDKSharePhoto alloc] init];
photo.image = sharedImage;
photo.userGenerated = YES;
FBSDKSharePhotoContent *content = [[FBSDKSharePhotoContent alloc] init];
content.photos = @[photo];
[FBSDKShareDialog showFromViewController:self.presentController withContent:content delegate:self];

//最后通过代理方法来得到用户是分享还是取消了
- (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results {
    self.block(ShareResultStateSuccessed);
}

- (void)sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error{
    self.block(ShareResultStateFailed);
}

视频分享

官方参考https://developers.facebook.com/docs/sharing/ios

主要是视频的URL必须是asset url,否则会报错。具体URL见下面代码。代理方法处理同上面的图片。

[FileUtils saveVideoToCameraRollWithFileUrl:[NSURL URLWithString:_emojiPath] completion:^(CameraRollSaveStatus status, NSString *localID) {
    if (status == CameraRollSaveStatus_SaveSuccess) {

        NSString *urlString = [NSString stringWithFormat:@"assets-library://asset/asset.MP4?id=%@&ext=MP4", [localID componentsSeparatedByString:@"/"].firstObject ];

        dispatch_async(dispatch_get_main_queue(), ^{
            FBSDKShareVideo *video = [FBSDKShareVideo videoWithVideoURL:[NSURL URLWithString:urlString]];
            FBSDKShareVideoContent *content = [[FBSDKShareVideoContent alloc] init];
            content.video = video;
            [FBSDKShareDialog showFromViewController:self.presentController withContent:content delegate:self];
        });
    }
    else {
        self.block(ShareResultStateFailed);
    }
}]

Instagram分享

官方参考文档https://www.instagram.com/developer/mobile-sharing/iphone-hooks/,图片说明到是还可以(也许我是对着code看所以清晰),视频分享就不知所云了。

图片分享

//得到分享数据的data
NSData *sharedImageData = ...;

//将数据sharedImageData转成instagram的igo格式文件
if (!imageData || !file) {
    return NO;
}
NSString *pathImage = [NSTemporaryDirectory() tringByAppendingPathComponent:"zmojiinstagram.igo"];
NSURL *urlImage = [imageData writeToFile:pathImage atomically:YES] ? [NSURL fileURLWithPath:pathImage] : nil;
if (urlImage == nil) {
    self.block(ShareResultStateFailed);
    return NO;
}

//使用UIDocumentInteractionController分享图片
NSDictionary *annotation = @{@"InstagramCaption": @""};
BOOL result = [self shareViaInteractionControllerWithURL:urlImage andUTI:@"com.instagram.exclusivegram" andAnnotation:annotation];
return result;


//以下是辅助函数
- (BOOL)shareViaInteractionControllerWithURL:(NSURL *)url andUTI:(NSString *)uti andAnnotation:(id)annotation {
    UIDocumentInteractionController *controller;
    if (url) {
        controller = [UIDocumentInteractionController interactionControllerWithURL:url];
    } else {
        controller = [[UIDocumentInteractionController alloc] init];
    }
    if (uti) {
        controller.UTI = uti;
    }
    if (annotation) {
        controller.annotation = annotation;
    }
    controller.delegate = self;
    self.interactionController = controller;
    UIView *view = self.presentController.view;
    CGRect rect = CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.width);
    return [controller presentOpenInMenuFromRect:rect inView:view animated:YES];
}

- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller {
    self.interactionController = nil;
    if (_interactionOptionSelected) {
        self.block(ShareResultStateUnknown);
    } else {
        self.block(ShareResultStateCancelled);
    }
    _interactionOptionSelected = NO;
}

视频分享

这里需要使用openURL这个API,具体参数https://useyourloaf.com/blog/openurl-deprecated-in-ios10/

思路是这样的:由于只允许分享相册中的视频,我们需要把自己的视频存入相册(需要权限),然后拿到这个视频的asset url,使用URL Scheme来分享视频,url为:instagram://library?AssetPath=%@&InstagramCaption=%@,%@为占位符。与Facebook SDK比这个就不知道用户是分享了还是取消了。

if ([[NSFileManager defaultManager] fileExistsAtPath:_emojiPath]) {
            //先将文件写入系统相册中,结束后使用PHAsset的localIdentifier转化成asset url
            [FileUtils saveVideoToCameraRollWithFileUrl:[NSURL URLWithString:_emojiPath] completion:^(CameraRollSaveStatus status, NSString *localID) {
                if (status == CameraRollSaveStatus_SaveSuccess) {
                    NSString *instagramURL = [NSString stringWithFormat:@"instagram://library?AssetPath=%@&InstagramCaption=%@",[self encodeToPercentEscapeString:(NSString *)[localID componentsSeparatedByString:@"/"].firstObject],[self encodeToPercentEscapeString:@""]];
                    [self openScheme:instagramURL];
                    self.block(ShareResultStateSuccessed);
                }
                else {
                    self.block(ShareResultStateFailed);
                }
            }];
            return NO;
        }
        else {
            self.block(ShareResultStateFailed);
            return NO;
        }


//以下是辅助函数
- (void)openScheme:(NSString *)scheme {
    UIApplication *application = [UIApplication sharedApplication];
    NSURL *URL = [NSURL URLWithString:scheme];

    if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) {
        [application openURL:URL options:@{}
           completionHandler:^(BOOL success) {
               NSLog(@"Open %@: %d",scheme,success);
           }];
    } else {
        BOOL success = [application openURL:URL];
        NSLog(@"Open %@: %d",scheme,success);
    }
}

-(NSString *)encodeToPercentEscapeString:(NSString *)string {
    return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
                                                                                 (CFStringRef) string,
                                                                                 NULL,
                                                                                 (CFStringRef) @"!*'();:@&=+$,/?%#[]",
                                                                                 kCFStringEncodingUTF8));
}

-(NSString *)decodeFromPercentEscapeString:(NSString *)string {
    return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,
                                                                                                 (CFStringRef) string,
                                                                                                 CFSTR(""),
                                                                                                 kCFStringEncodingUTF8));
}

总之,需要将视频放入系统相册才能分享。这真坑