因为公司的项目里集成了一键分享的这个模块, 而在我设计的时候发现国内的官方文档和提供的 Sample 有混乱和容易混淆的地方, 而且除了普通的网页、图片、文字分享到各大 Social 平台以外, 对于视频、文件和其他内容的分享 Demo 在百度或者 Google 几乎搜不到. 自己也是踩了很多坑才把很多问题解决.
测试设备
iPhone 7 Plus, iOS 11.4.1.
支持平台
RSHARE 这个 Demo 中支持: 微信、QQ、新浪微博、Facebook、GooglePlus(Google +)、Twitter、WhatsApp、Line、Tumblr、Instagram、Pinterest 11 个 Social 平台.
平台差异
主要罗列了常用的 5 个分享内容的对比菜单(网页、文字、图片、本地视频、文件).
注意菜单内字母以及菜单后面对应字母的注释⚠️
❤️ | 微信 | 微博 | Line | Tumblr | Google+ | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
网页 | ✓a | ✓ | ✓ | ✓b | ✓ | ✗ | ✓ | ✓ | ✓ | ✗ | ✓ |
文字 | ✓c | ✓ | ✓ | ✗ | ✓ | ✗ | ✓ | ✓ | ✓ | ✗ | ✗ |
图片 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓d | ✓d | ✗ |
视频 | ?e | ✗ | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
文件 | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
a. QQ 虽支持网页分享, 但是不允许带着网页的 description
字段, 且分享到 QQ 空间只支持通过文字分享, 这和 Android 表现不同;
b. Facebook 的网页分享支持 hashtag;
c. iOS 端分享文字到 QQ 客户端是可行的, 但是 Android 端不允许, 其实 QQ 的分享目地就是让用户自行输入有价值、有意义的文字信息, 这样可以过滤一部分广告, 但是 iOS 和 Android 端的不统一实在是不应该;
d. Pinterest 和 Tumblr 虽支持图片分享, 但仅仅支持分享图片的 URL, 它会自行解析并显示;
e. QQ 客户端分享分两类: 1 好友、收藏、数据线(我的电脑)分享; 2 QQ 空间分享. 本地视频的分享只支持 QQ 空间分享.
- 对比列表得知, 国内的平台分享内容是最丰富的, 但是存在一个主要的问题(主要是 QQ), iOS 和 Android 双端的接口以及实现的功能也并不统一(后面的部分会具体说); 微信双端当分享的图片过大的时候的表现也有不统一的时候, 其余都很完善; 新浪的表现是最统一的, 且没有过多限制; 国内的平台分享最让人头疼的就是官方的 Sample 很混乱, 但是在实践代码的时候还是要以官方为主.
- 国外的文档和 Sample 很明了且注释详细, 但也存在双端不统一的情况, Twitter 的双端表现就不一样(后面细说), 但是国外的平台分享几乎没有回调, Facebook 的回调只有 Feed 形式的分享才有效, Instagram、Line、Google+这些是没有 SDK 的, 仅仅是通过打开Application URL scheme 来分享.
分享总体设计
大概的分享逻辑如下:
iOS 的分享是参照各大平台的分享逻辑得到比较统一思路, 即: 先判断是否安装对应应用, 然后初始化 SDK 与官方平台连接, 然后包装分享参数进行分享, 最后处理分享回调.
- 有些平台不存在 SDK, 所以直接判断是否平台安装然后包装分享参数进行分享;
- Tumblr 比较特殊, 有 SDK 但是不需要判断应用是否安装就可以分享, Twitter 也如此, 具体情况在 Twitter 的部分说明;
- SDK 的初始化, 统一函数名字为
sdkInitialize
,Key
、Secret
以及AppID
等信息在注释中有标明.
详细逻辑
关于各个平台的开发者主页和文档信息以这里为主, 代码注释的可能不准确.
平台分享都是通过单例模式实现.
在手动导入框架的时候尽量, 放在项目根目录下然后通过下图的方式导入:
在项目级
Framework
目录下右键执行Add Files to "name"
.
子平台分享完毕返回到本应用的接口再封装 Objective-C 版本用的是实例方法, Swift 版本使用的是类方法.
基类
基类都是继承自RShare, 这个类中定义了分享 Mode(代码注释中有标明, iOS 中使用范围较小)、分享结果 ShareResult (成功、取消、失败)以及最重要的回调.
回调:
Objective-C:
typedef void (^RShareCompletion)(RShareSDKPlatform platform, ShareResult result, NSString* _Nullable errorInfo);
Swift:
typealias RShareCompletion = (_ paltform : RShareSDKPlatform,_ result : ShareResult,_ errorInfo : String?) -> Void
Mode(仅对 Facebook、Twitter、Instagram 有效, Android 亦然):
Objective-C:
typedef NS_ENUM(NSInteger, Mode) {
/**
@Displays 优先选择原生应用分享, 原生应用未安装的情况可能跳转内置 WebView 或者 Safari 进行分享.
*/
ShareModeAutomatic,
/**
@Displays 原生应用分享.
*/
ShareModeNative,
/**
@Displays 应用内置 UIWebView 分享.
*/
ShareModeWeb,
/**
@Displays the dialog in the iOS integrated share sheet, 仅对 Facebook 分享有效.
*/
ShareModeSheet,
/**
@Displays 跳转至 Safari 分享, 仅对 Facebook 分享有效.
*/
ShareModeBrowser,
/**
@Displays 跳转至 Safari 进行 Feed 形式的分享, 仅对 Facebook 分享有效.
*/
ShareModeFeedBrowser,
/**
@Displays 应用内置 UIWebView 的 Feed 形式分享, 仅对 Facebook 分享有效.
*/
ShareModeFeed,
/**
@Displays iOS 的系统分享.
*/
ShareModeSystem
};
准备
分享需要注册平台, 腾讯开发者主页, SDK 下载, QQ SDK 目前不支持 pod 安装, iOS API 调用说明文档.
集成
a. TencentOpenAPI.framework
导入项目中;
b. 添加系统依赖Security.framework
、SystemConfiguration.framework
、CoreGraphic.framework
、libsqilte3.0.tbd
、CoreTelephony.framework
、libz.tbd
.
c. 设置 The Other Flags 为 -ObjC.
d. 在info.plist
文件的CFBundleURLTypes
中添加:
CFBundleURLSchemes
tencentYOURAPPID
e. 添加以下至白名单:
mqq
mqqapi
mqqwpa
mqqbrowser
mttbrowser
mqqOpensdkSSoLogin
mqqopensdkapiV2
mqqopensdkapiV3
mqqopensdkapiV4
wtloginmqq2
mqzone
mqzoneopensdk
mqzoneopensdkapi
mqzoneopensdkapi19
mqzoneopensdkapiV2
mqqapiwallet
mqqopensdkfriend
mqqopensdkdataline
mqqgamebindinggroup
mqqopensdkgrouptribeshare
tencentapi.qq.reqContent
tencentapi.qzone.reqContent
f. Swift 语言集成需要 Objective-C - Swift 桥接文件.
接口调用及内部实现
a. 初始化 SDK
Objective-C:
[[RQqManager shared] sdkInitializeByAppID:yourAppId appKey:yourAppKey];
Swift:
RQqManager.shared.sdkInitialize(appID: yourAppId, appKey: yourAppKey)
内部实现 (Objective-C):
[[TencentOAuth alloc]initWithAppId:appID andDelegate:self];
由此看出, 其实仅仅是用作分享功能的话, 是不需要
appKey
这个字段的.
b. 分享
对于分享内容的包装, 通过建立 RQqHelper 来实现分享内容的处理和平台 Manager 的分隔, 这样有利于逻辑的处理, 结构明显, 代码可控.
关于参数包装的细节, 没什么好细说的, QQ 提供的接口简单明了(Android 不是这样).
另, 除在 QQApiInterfaceDelegate
代理函数 - (void)onResp:(QQBaseResp *)resp
中处理分享回调外, 在发起手 Q 分享请求的接口 [QQApiInterface sendReq: request]
返回的 QQApiSendResultCode 做了分享失败的请求码处理, Objective-C 中单独建立的处理函数 - (void)handleResultCode:(QQApiSendResultCode)code
, Swift 则直接在 resultCode 的 set 方法
处理.
分享到 QQ 的接口中 scene
字段细分到 QQ 好友、我的收藏、数据线(我的电脑), 但 Android 中不支持直接打开‘我的收藏’和‘数据线(我的电脑)’面板, 须自行选择.
文字分享:
Objective-C:
[[RQqManager shared] shareTextToQQ:text scene:scene completion:completion];
Swift:
RQqManager.shared.share(text: text, scene: scene, completion: completion)
表现(QQ 好友分享):
图片分享:
Objective-C:
[[RQqManager shared] shareImageToQQ:targetImage title:title description:description scene:scene completion:completion];
Swift:
RQqManager.shared.share(image: targetImage, title: title, description: description, scene: scene, completion: completion)
表现(QQ 好友分享):
网页分享:
Objective-C:
[[RQqManager shared] shareWebpageToQQWithURL:webpageURL title:title description:description thumbImage:image scene:scene completion:completion];
Swift:
RQqManager.shared.share(webpageURL: webpageURL, title: title, description: description, thumbImage: image, scene: scene, completion: completion)
表现(QQ 好友分享):
视频链分享:
实质就是网页的分享, 在此不作代码示例.
音频链分享:
大致和网页的分享相同, 但是多了一个 streamURL
的字段.
Objective-C:
[[RQqManager shared] shareAudioToQQWithStreamURL:audioStreamURL title:title description:description thumbImage:image webpageURL:webpageURL scene:scene completion: completion];
Swift:
RQqManager.shared.share(audioStreamURL: audioStreamURL, title: title, description: description, thumbImage: image, webpageURL: webpageURL, scene: scene, completion: completion)
⚠️ 1.
Tencent.framework
中QQApiVideoObject
的flashURL
属性设置音频流.
⚠️ 2.audioStreamURL
请设置音频的音频流链接, 不要把音乐平台分享的音乐网链直接赋值在该字段上, 否则点击播放按钮是无法播放的, 音乐网链是放在webpageURL
字段上的.
表现(QQ 好友分享):
文件分享:
Objective-C:
[[RQqManager shared] shareFileToQQWithFileData:fileData fileName:fileName title:title description:description thumbImage:image completion: completion];
Swift:
RQqManager.shared.share(fileData: filedata, fileName: fileName, title: title, description: description, thumbImage: image, compeltion: completion)
⚠️ 1.
fileName
字段设置方式是: ‘文件名’+‘.扩展名’, 形如:HelloWorld.doc, 这样 QQ 系统内部能够解析并且可以友好的展示分享内容, 经测试大部分常规的文件都能友好的展示.
⚠️ 2. 文件分享只支持 QQ 客户端数据线(我的电脑)分享, 并且 Android 端无法分享文件, 也或许其实是可以分享文件只不过本人技拙没发现实现方法罢.
表现(以视频为例):
文字分享到 QQ 空间:
Objective-C:
[[RQqManager shared] shareTextToQZone:description completion: completion];
Swift:
RQqManager.shared.share(text: description, completion: completion)
⚠️ Android 端不支持纯文字分享到 QQ 空间, 且 iOS 端不支持网页分享到 QQ 空间, 除非把字符串形式的网链通过文字的方式分享, 这是可行的.
表现:
分享图片到 QQ 空间:
Objective-C:
[[RQqManager shared] shareImagesToQZone: targetImageArray description:description completion: completion];
Swift:
RQqManager.shared.share(images: targetImageArray, description: description, completion: completion)
⚠️
description
字段实际是失效的, 但不保证未来一定不用这个字段, 所以暂且保留这个字段.
表现:
分享本地视频到 QQ 空间:
Objective-C:
[[RQqManager shared] shareVideoToQZoneWithAssetURL:videoAssetURL description:description completion: completion];
Swift:
RQqManager.shared.share(videoAssetURL: videoAssetURL, description: description, completion: completion)
⚠️ 1.
description
字段实际是失效的.
⚠️ 2. 本地视频 URL 为通过UIImagePickerController
选择的媒体 info 的UIImagePickerControllerReferenceURL
的值, 形如: assets-library://asset/asset.MP4?id=8FF2F03F-DD84-41A5-A20C-B745E793C0DC&ext=MP4
表现:
c. 返回本应用
Objective-C:
[[RQqManager shared] application:app openURL:url options: options];
Swift:
RQqManager.application(app, open: url, options : options)
微信
准备
分享需要注册平台, 微信开放平台, SDK 下载, 微信 SDK 支持 pod 安装, 分享 & 收藏 API 调用说明.
集成
a. 手动: libWeChatSDK.a
、WXApi.h
、WXApiObject.h
, 导入项目中;
pod 集成: pod 'WechatOpenSDK'
, 若出现:
Use the
(inherited)**, Other Linker Flags 中 -all_load 替换成 $(inherited).
b. 添加系统依赖 SystemConfiguration.framework
, libz.dylib
, libsqlite3.0.dylib
, libc++.dylib
, Security.framework
, CoreTelephony.framework
, CFNetwork.framework
.
c. 手动集成的情况下, 需设置 The Other Flags 为 -ObjC.
d. 在info.plist
文件的 CFBundleURLTypes
中添加:
CFBundleURLSchemes
wxYOURAPPID
e. 添加以下至白名单:
weixin
wechat
f. Swift 语言集成需要 Objective-C - Swift 桥接文件.
接口调用及内部实现
a. 初始化 SDK
Objective-C:
[[RWechatManager shared] sdkInitializeByAppID:appID appSecret:secret];
Swift:
RWechatManager.shared.sdkInitialize(appID: appID, appSecret: secret)
仅做分享功能的话,
secret
字段无用.
初始化内部实现略微有区别:
Objective-C:
UInt64 typeFlag = MMAPP_SUPPORT_TEXT | MMAPP_SUPPORT_PICTURE | MMAPP_SUPPORT_VIDEO | MMAPP_SUPPORT_LOCATION | MMAPP_SUPPORT_AUDIO | MMAPP_SUPPORT_WEBPAGE;
[WXApi registerAppSupportContentFlag:typeFlag];
[WXApi registerApp:appID];
Objective-C 中同时设置多个枚举值可以通过 '|' 来实现 option 的设置.
Swift:
let typeFlag : TypeFlag = [.Text, .Picture, .Video, .Audio, .Webpage]
WXApi.registerAppSupportContentFlag(typeFlag.rawValue)
WXApi.registerApp(appID)
Swift 中设置多个枚举值不可用 '|' 来实现, 想要达到这样的效果, 必须新建结构体并且实现
OptionSetType
协议,OptionSetType
改变了 Objective-C 中NS_ENUM
/NS_OPTIONS
的行为方式赋予可多选的能力.
TypeFlag 的声明(没有写全, 但实际测试并不影响文件的分享):
private struct TypeFlag : OptionSet {
let rawValue: UInt64
static let Text = TypeFlag(rawValue: enAppSupportContentFlag.MMAPP_SUPPORT_TEXT.rawValue)
static let Picture = TypeFlag(rawValue: enAppSupportContentFlag.MMAPP_SUPPORT_PICTURE.rawValue)
static let Video = TypeFlag(rawValue: enAppSupportContentFlag.MMAPP_SUPPORT_VIDEO.rawValue)
static let Audio = TypeFlag(rawValue: enAppSupportContentFlag.MMAPP_SUPPORT_AUDIO.rawValue)
static let Webpage = TypeFlag(rawValue: enAppSupportContentFlag.MMAPP_SUPPORT_WEBPAGE.rawValue)
}
b. 分享
微信分享的内容包装同样通过一个 RWechatHelper
进行单独处理, 对于文字、网页、图片、视频网链、小程序、文件的分享内容处理都很简单, 特别注意的就是对于音乐链的分享, 同 QQ 一样, 需要区别两个参数, 一个是音频流链, 一个是音频网页, 播放的是音频流, 点击背景进入的是音频网页.
Objective-C:
WXMusicObject* obj = [WXMusicObject object];
obj.musicDataUrl = musicURL;
obj.musicUrl = webpageURL;
Swift:
let obj = WXMusicObject()
obj.musicUrl = audioStreamURL
obj.musicUrl = webpageURL
文字分享:
Objective-C:
[[RWechatManager shared] shareText:text scene: scene completion: completion];
Swift:
RWechatManager.shared.share(text: shareDescription, scene: scene, completion: shareCompletion)
表现(分享到好友):
图片分享:
Objective-C
[[RWechatManager shared] shareImage:targetImage scene: scene completion: completion];
Swift:
RWechatManager.shared.share(image: targetImage, scene: scene, completion: completion)
表现(分享到好友列表):
网页分享:
Objective-C:
[[RWechatManager shared] shareWebpageWithURL:webpageURL title:title description:description thumbImage:thumbImage scene: scene completion: completion];
Swift:
RWechatManager.shared.share(webpageURL: webpageURL, title: title, description: description, thumbImage: thumbImage, scene: scene, completion: completion)
⚠️ 1.
thumbImage
字段的缩略图大小不能超过 32 Kb, 但实际测试 100 Kb 左右也是完全可行的, 但一定不能过大, 否则会出现:分享 N 次才能成功一次, 或者干脆无法调起微信的客户端进行分享.
⚠️ 2. Android 对于缩略图的处理相对友好很多, 对于 iOS 无法分享的过大的缩略图数据一般情况下 Android 都能成功启动微信客户端并且成功分享(亲测).
⚠️ 3. 在缩略图没有符合规范的时候, 即使成功分享在 iOS 端也会出现缩略图不显示的情况, Android 几乎都会显示.
表现(分享到好友):
视频链分享:
实质就是网页的分享, 在此不作代码示例.
音频链分享:
Objective-C:
[[RWechatManager shared] shareMusicWithStreamURL: audioStreamURL webpageURL:audioWebpageURL title: title description: description thumbImage:image scene:scene completion: completion];
Swift:
RWechatManager.shared.share(audioStreamURL: audioStreamURL, webpageURL: audioWebpageURL, title: title, description: description, thumbImage: thumbImage, scene: scene, completion: completion)
⚠️ 注意
audioStreamURL
和webpageURL
的区别, 前面有提及.
表现(分享到微信好友):
小程序分享:
Objective-C:
[[RWechatManager shared] shareMiniProgramWithUserName:userName path:path type:type webpageURL:webpageURL title:title description:description thumbImage:image scene: scene completion: completion];
Swift:
RWechatManager.shared.shareMiniProgram(userName: userName, path: path, type: type, webpageURL: webpageURL, title: title, description: description, thumbImage: thumbImage, scene: scene, completion: completion)
⚠️ 1. demo 中笔者并没有编写小程序, 仅仅依照微信的 SDK 进行了参数的设置, 所以无法分享, 但具体的参数设置形式在 demo 中明确标明.
⚠️ 2. 小程序分三种类型,type
字段分: 发布、预览以及体验三个版本.
文件分享:
Objective-C:
[[RWechatManager shared] shareFileWithData:fileData extension:fileExtensionName title:title thumbImage:image scene:scene completion: completion];
Swift:
RWechatManager.shared.share(fileData: fileData, extensionName: fileExtensionName, title: title, thumbImage: thumbImage, scene: scene, completion: completion)
对于体积稍大的图片、小体积视频、doc 文本、PDF 文件 都测试过, 可以正常分享, 且通过微信内部的解析可以显示.
⚠️ 1. 必须设置文件的扩展名.
⚠️ 2. 文件分享不支持分享到朋友圈.
⚠️ 3. 在设置缩略图的情况下, iOS 端的对话框是不显示缩略图的, 但是 Android 可以, 但也仅限于发送方能看见.
表现(分享视频到微信好友):
c. 返回本应用
Objective-C:
[[RWechatManager shared] application:app openURL:url options:options];
Swift:
RWechatManager.application(app, open: url, options : options)
新浪
准备
分享需要注册平台, 新浪开放平台, SDK 下载, 新浪 SDK 支持 pod 安装, iOS 接口调用文档.
集成
a. 手动导入 WeiboSDK.h
、 WBHttpRequest.h
、libWeiboSDK.a
和 WeiboSDK.bundle
到项目中.
pod 集成: pod "Weibo_SDK", :git => "https://github.com/sinaweibosdk/weibo_ios_sdk.git"
(未实际测试过).
b. 添加系统依赖QuartzCore.framework
、SystemConfiguration.framework
、ImageIO.framework
、CoreGraphic.framework
、Security.framework
、libsqilte3.0.tbd
、CoreTelephony.framework
、CoreText.framework
、libz.tbd
.
c. 设置 The Other Flags 为 -ObjC.
d. 在 info.plist
文件的 CFBundleURLTypes
中添加:
CFBundleURLSchemes
wbYOURAPPKEY
e.对传输安全的支持, 在当下的 iOS 系统中,默认需要为每次网络传输建立 SSL, 所以需在 plist 中设置 NSAppTransportSecurity 的 NSAllowsArbitraryLoads 为 YES.
f. 解除原有 ATS设置在 iOS 10+ 的网络限制:
sina.com.cn
NSIncludesSubdomains
NSThirdPartyExceptionAllowsInsecureHTTPLoads
NSExceptionMinimumTLSVersion
TLSv1.0
NSThirdPartyExceptionRequiresForwardSecrecy
g. 添加以下至白名单:
sinaweibohd
sinaweibo
weibosdk
weibosdk2.5
h. Swift 语言集成需要 Objective-C - Swift 桥接文件.
接口调用及内部实现
a. 初始化 SDK
Objective-C:
[[RSinaWeiboManager shared] sdkInitializeByAppKey:YourAppKey appSecret:YourAppSecret];
Swift:
RSinaWeiboManager.shared.sdkInitialize(appKey: YourAppKey, appSecret: YourAppSecret)
仅做分享的话,
secret
字段无用.
b. 分享
对于分享内容的包装新浪处理的比 QQ 简练, 所以无需借助新的类去处理分享内容, 文字是最简单的, 不需要对文字内容进行二次包装, 直接对 WBMessageObject
进行文字设置然后发送分享请求即可;
图片和视频(包括到「微博故事」)的分享需要 WBImageObject
和 WBNewVideoObject
的包装, 执行 addImages
和 addVideo
方法将要分享的图片/视频处理, 在此需要注意的是:实例化 WBImageObject
和 WBNewVideoObject
的时候必须设置 delegate, 并实现 WBMediaTransferProtocol
协议, 由于 addImages
和 addVideo
是异步操作, 所以 wbsdk_TransferDidReceiveObject
回调中发送分享请求!
另, 经测试, 在参数准备失败的回调函数 wbsdk_TransferDidFailWithErrorCode
中, 出现的错误场景总结:
- 图片、视频体积过大;
- 图片数量不在 1 ~ 9 范围内;
- 倘若分享到「微博故事」, 照片只能分享一张, 而传了多张图片;
WBImageObject
多参数并存: 单张的 Data 格式的图片和图片数组共存;- 视频 URL 错误.
文字分享:
Objective-C:
[[RSinaWeiboManager shared] shareText: text completion: completion];
Swift:
RSinaWeiboManager.shared.share(text: text, completion: completion)
表现:
图片分享:
Objective-C:
[[RSinaWeiboManager shared] shareImage:images text: text toStory: yesOrNo completion: completion];
Swift:
RSinaWeiboManager.shared.share(images: images, text: text, isToStory: trueOrFalse, completion: completion)
为统一接口, 图片用数组包装; 分享到「微博故事」功能中 text
字段会失效.
⚠️ 1. 开启「分享到微博故事」功能图片只能传一张; 多张图片分享的情况下「分享到微博故事」的功能必须关闭!
⚠️ 2. 图片单张不能超过 10 MB, 最多 9 张图片.
表现:
分享到微博:
分享到「微博故事」:
本地视频分享:
Objective-C:
[[RSinaWeiboManager shared] shareVideoWithLocalURL:videoFileURL text:text toStory:YesOrNo completion: completion];
Swift:
RSinaWeiboManager.shared.share(localVideoURL: videoFileURL, text: text, isToStory: trueOrFalse, completion: completion)
分享到「微博故事」功能中 text
字段会失效.
⚠️ 本地视频 URL 为通过
UIImagePickerController
选择的媒体 info 的UIImagePickerControllerMediaURL
的值,形如: file:///private/var/mobile/Containers/Data/Application/3B368706-001D-4018-901B-284D64FA50E2/tmp/17BD98B4-A498-46E7-9715-6F39E73DFD75.MOV
表现:
分享到微博:
分享到「微博故事」:
网页分享:
Objective-C:
[[RSinaWeiboManager shared] shareWebpageWithURL: webpageURL objectID: @"id" title: title description: description thumbImage:thumbImage completion: completion];
Swift:
RSinaWeiboManager.shared.share(webpageURL: webpageURL, objectID: "id", title: title, description: description, thumbImage: thumbImage, completion: completion)
objectID
字段用于表示一个多媒体内容; 网页的消息体设置无需设置 delegate, 因为不涉及异步操作, 而且 thumbImage
字段应该是失效的, 即不显示缩略图.
⚠️ 1. 网页
thumbImage
字段的缩略图数据不能大于 32 Kb (新浪的 SDK 控制的很严格).
⚠️ 2.WBWebpageObject
的description
设置无效, 想要显示网页的相关描述, 只能设置WBMessageObject
的text
字段.
表现:
c. 返回本应用
Objective-C:
[[RSinaWeiboManager shared] application:app openURL:url options:options];
Swift:
RSinaWeiboManager.application(app, open: url, options : options)
准备
分享需要注册平台, Facebook 开发者主页, Facebook SDK 支持 pod 集成, 分享接口调用说明.
集成
a. pod 集成: pod 'FBSDKLoginKit'
b. 在info.plist
文件的CFBundleURLTypes
中添加:
CFBundleURLSchemes
fbYOURAPPID
FacebookAppID
YOURAPPID
FacebookDisplayName
SOMENAME
c. 添加以下至白名单:
fbapi
fb-messenger-share-api
fbauth2
fbshareextension
d. Swift 语言集成需要 Objective-C - Swift 桥接文件.
接口调用及内部实现
a. 初始化 SDK
Objective-C:
[[RFacebookManager shared] sdkInitializeByID:appID secret:secret];
Swift:
RFacebookManager.shared.sdkInitialize(appID: appID, secret: secret)
仅做分享功能的话,
secret
字段无用.
b. 分享
参数的包装, 借助工具类 RFacebookHelper
来处理, Facebook 已经封装好了各个类型的分享内容载体 (FBSDKSharePhotoContent、FBSDKShareVideoContent ...), 对应设置属性值就可以; 对于图片的分享, 和新浪的图片分享思路相同, 即: 无论是单张还是多图, 一概通过数组包装传递给 RFacebookHelper
, 然后它自行处理.
网页分享:
Objective-C:
[[RFacebookManager shared] shareWebpageWithURL: webpageURL
quote: quote
hashTag: hashTag
from: context
mode: mode
completion: completion];
Swift:
RFacebookManager.shared.share(webpageURL: webpageURL, quote: quote, hashTag: hashTag, from: context, mode: mode, completion: completion)
Facebook 的 SDK 在迭代的过程中, 舍弃了很多字段, 分享参数不如新浪那样多样, 但是其分享的表现形式却比国内的要友好很多, 特别是在网页分享这块体现的更加明显, 值得注意的是, 非网页形式的分享回调无效, 努力地在 Github、Stack Overflow 和 Facebook Developer 论坛找答案但都没有找到解决办法, 根据 postId
的判断分享结果状态的方法早已失效, 无论是 Android 还是 iOS 端, 目前都没办法.
⚠️
hashTag (话题)
的表现形式不同于国内, 新浪的话题格式: #话题#, 两个 # 之间一切内容都能成为话题, 而 Twitter、Instagram、Facebook 的格式: #话题, 话题内容词组之间不能有任何符号且必须连在一起.
表现:
客户端形式的分享(无回调):
由上图可见, 在通过客户端分享的过程中, quote
字段已经丢失, Android 表现不同, quote
保留, 其次, iOS 是跳转到 Facebook 客户端分享, Android 是在本应用内弹出对话框分享, 且 Android 通过客户端分享需要提前打开 Facebook 客户端, 否则无法弹出分享对话框, 测试过美图秀秀的图片分享, 也是一样, 需要提前打开客户端.
网页形式的分享(有回调):
图片分享:
Objective-C:
[[RFacebookManager shared] sharePhotos: targetImageArray
from:context
completion: completion];
Swift:
RFacebookManager.shared.share(photos: targetImageArray, from: context, completion: completion)
⚠️ 1. 照片大小必须小于 12MB.
⚠️ 2. 用户需要安装版本 7.0 或以上的原生 iOS 版 Facebook 应用.
表现:
本地视频分享:
Objective-C:
[[RFacebookManager shared] shareVideoWithLocalURL: videoURL from: context];
Swift:
RFacebookManager.shared.share(localVideoURL: videoURL, from: context)
⚠️ 本地视频 URL 为通过
UIImagePickerController
选择的媒体 info 的UIImagePickerControllerReferenceURL
的值, 形如: assets-library://asset/asset.MP4?id=8FF2F03F-DD84-41A5-A20C-B745E793C0DC&ext=MP4
倘若通过 Facebook 的 SDK 自行构建本地视频分享模型, 需注意 iOS 11 前后的模型属性设置不同:
Objective-C:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
FBSDKShareVideo *video = [[FBSDKShareVideo alloc] init];
if (@available(iOS 11, *)) {
video.videoAsset = [info objectForKey:UIImagePickerControllerPHAsset];
} else {
video.videoURL = [info objectForKey:UIImagePickerControllerReferenceURL];
}
...
}
Swift:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let video = FBSDKShareVideo()
if #available(iOS 11, *) {
video.videoAsset = info[UIImagePickerControllerPHAsset]
} else {
video.videoURL = info[UIImagePickerControllerReferenceURL]
}
...
}
为了统一使用 URL 分享本地视频, 所以笔者并没有考虑使用上述的写法.
表现:
C. 返回本应用
Objective-C:
[[RFacebookManager shared]application:app openURL:url options:options];
Swift:
RFacebookManager.application(app, open: url, options : options)
d. 其他设置
在完成 Facebook 登录、分享等操作的时候还需要连接本应用的 AppDelegate
, 故在 didFinishLaunchingWithOptions
函数中添加:
Objective-C:
[[RFacebookManager shared] application:application didFinishLaunchingWithOptions:launchOptions];
Swift:
RFacebookManager.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
当需要记录有多少用户激活的时候需要在 applicationDidBecomeActive
方法中添加:
Objective-C:
[[RFacebookManager shared]applicationDidBecomeActive:application];
Swift:
RFacebookManager.shared.applicationDidBecomeActive(application)
准备
分享需要注册平台, Twitter 开发者主页, 注册应用主页, Twitter SDK 支持 pod 集成, 分享接口调用说明.
⚠️: Twitter SDK 将于 2018/10/31 后不再进行维护, 但是不影响后续使用, 需自行维护, Twitter 产品经理 Neil Shah 对 Twitter SDK 放弃维护迭代的声明博客.
集成
a. pod 集成: pod 'TwitterKit'
b. 在 info.plist
文件的CFBundleURLTypes
中添加:
CFBundleURLSchemes
twitterkit-YOURCONSUMERKEY
c. 添加以下至白名单:
twitter
twitterauth
d. Swift 语言集成需要 Objective-C - Swift 桥接文件.
接口调用及内部实现
a. 初始化 SDK
Objective-C:
[[RTwitterManager shared] sdkInitializeByConsumerKey:yourConsumerKey consumerSecret:yourConsumerSecret];
Swift:
RTwitterManager.shared.sdkInitialize(consumerKey: consumerKey, consumerSecret: secret)
仅做分享的话,
secret
字段无用.
b. 授权 Twitter 客户端
与其他平台分享不同的是, Twitter 在进行发推(分享)的时候会先进行检测本地的 SessionStore
的标记判断是否登录(授权)过, 所以在进行发推的时候需要进行这一步的判断, 在未登录的情况下需进行授权, 在此使用 RTwitterAuthHelper
进行处理, 登录(授权回调):
Objective-C:
typedef void (^auth)(RTWAuthState state, NSString* _Nullable errorInfo);
Swfit:
typealias RTWAuthCompletion = (_ state : RTWAuthState,_ errorInfo : String?) -> Void
state
包括成功和失败两种结果.
判断是否登录过:
Objective-C:
BOOL flag = [[RTwitterAuthHepler shared] hasLogged];
Swift:
let _ = RTwitterAuthHepler.shared.hasLogged
登录授权:
Objective-C:
[[RTwitterAuthHelper shared]authorizeTwitter:^(RTWAuthState state, NSString * _Nullable errorInfo) {
// some code ...
}];
Swift:
RTwitterAuthHepler.shared.authorizeTwitter { (state, errorInfo) in
// some code ...
}
这一步目前的情况就是把 Twitter SDK 提供的授权方法重新包装写了遍, 但是考虑到未来可能用到 session
和 token
等信息并处理, 所以单独写了类讲授权和分享隔离.
返回本应用:
Twitter 分享是不需要进行程序跳转的, 只有在登录授权的时候才会需要下述方法, 所以当你成功授权了以后卸载掉 Twitter 的客户端依然可以进行分享.
Objective-C:
[[RTwitterManager shared] application:app openURL:url options:options];
Swift:
RTwitterManager.application(app, open: url, options : options)
⚠️ Twitter 最新 SDK 要求项目的
Deloyment Target
至少为 9.0.
c. 分享
在本人写的 demo 中, 分享和登录授权是衔接的, 即: 若未登录过 -> 登录授权 -> 分享.
另, Twitter 能分享的内容相对较少, 所以关于文字、网页、图片的分享, 统一到一个分享接口里, 三者不能同时为空.
Objective-C:
[[RTwitterManager shared]shareWithWebpageURL: webpageURL text: text image: image from: context completion: completion];
Swift:
RTwitterManager.shared.share(webpageURL: webpageURL, text: text, image: image, from: context, completion: completion)
表现:
Twitter 分享是在本应用内弹出分享框进行分享.
准备
分享无需注册平台无需 SDK, Instagram 开发者主页, Custom URL Scheme 方式分享.
配置
在info.plist
文件中:
添加以下至白名单:
instagram
接口调用及内部实现
分享
无论照片还是视频都是通过 Custom URL Scheme 来打开 Instagram 客户端, 但 demo 中实际的方法和 Instagram 提供的 Custom URL不同.
Objective-C:
static NSURL* instagramLibraryURL() {
NSString *str = [NSString stringWithFormat:@"instagram://library?AssetPath=%@", @""];
return [NSURL URLWithString:str];
}
Swift:
fileprivate let instagramURL = URL(string: String(format: "instagram://library?AssetPath=%@", "" as CVarArg))
分享流程是先保存照片/视频再分享.
保存照片:
Objective-C
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), (__bridge void *)self);
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if ([[UIApplication sharedApplication] canOpenURL:instagramLibraryURL()]) {
[[UIApplication sharedApplication] openURL:instagramLibraryURL()];
}
}
Swift:
UISaveVideoAtPathToSavedPhotosAlbum(localVideoURL.path, self, #selector(video(path:didFinishSavingWithError:contextInfo:)), nil)
@objc fileprivate func image(image: UIImage!, didFinishSavingWithError error: NSError!, contextInfo: AnyObject!) {
if UIApplication.shared.canOpenURL(instagramURL!) {
UIApplication.shared.openURL(instagramURL!)
}
}
保存视频:
Objective-C:
UISaveVideoAtPathToSavedPhotosAlbum(localeVideoURL.path, self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
- (void)video:(NSString *)path didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if ([[UIApplication sharedApplication] canOpenURL:instagramLibraryURL()]) {
[[UIApplication sharedApplication] openURL:instagramLibraryURL()];
}
}
Swift:
UISaveVideoAtPathToSavedPhotosAlbum(localVideoURL.path, self, #selector(video(path:didFinishSavingWithError:contextInfo:)), nil)
@objc fileprivate func video(path: String!, didFinishSavingWithError error: NSError!, contextInfo: AnyObject!) {
if UIApplication.shared.canOpenURL(instagramURL!) {
UIApplication.shared.openURL(instagramURL!)
}
}
分享图片:
Objective-C:
[[RInstagramManager shared] share: targetImage];
Swift:
RInstagramManager.shared.share(image: targetImage)
表现:
分享本地视频:
Objective-C:
[[RInstagramManager shared]shareVideoWithLocalURL: videoURL description: description]
Swift:
RInstagramManager.shared.share(localVideoURL: videoURL, description: description)
description
字段在实际传递过程中是失效的.
表现:
⚠️ 本地视频 URL 为通过
UIImagePickerController
选择的媒体 info 的UIImagePickerControllerMediaURL
的值,形如: file:///private/var/mobile/Containers/Data/Application/3B368706-001D-4018-901B-284D64FA50E2/tmp/17BD98B4-A498-46E7-9715-6F39E73DFD75.MOV
Tumblr
准备
分享需要注册平台, Tumblr 开发者主页, 注册应用主页, Tumblr SDK 支持 pod 集成, 分享接口调用说明.
集成
a. pod 集成: pod 'Flurry-iOS-SDK/TumblrAPI'
⚠️: 一定是这个, 最新版本的 SDK 我没有找到分享的接口.
b. Swift 语言集成需要 Objective-C - Swift 桥接文件.
接口调用及内部实现
a. 初始化 SDK
Objective-C:
[[RTumblrManager shared] sdkInitializeByConsumerKey:yourConsumerKey consumerSecret: yourConsumerSecret];
Swift:
RTumblrManager.shared.sdkInitialize(consumerKey: yourConsumerKey, consumerSecret: yourConsumerSecret)
⚠️ 在 iOS 端初始化 SDK 需要
consumerKey
和consumerSecret
两个参数, Android 端还需要flurryKey
这个参数才能完成分享.
b. 分享
Tumblr 分享体只包括图片和文字两种, 并且图片还是网络图片的链接, 并不能分享本地图片, 所以 Tumblr 的局限性很大, 这两种分享体的模型通过 SDK 中 FlurryImageShareParameters
和 FlurryTextShareParameters
来构建;
Tumblr 分享是通过当前界面弹出对话框分享的, 和 Twitter 类似, 所以不需要判断 Tumblr 程序是否安装;
Tumblr 的分享流程是: 登录 -> 分享, 但是登录的逻辑不需要在代码中实现, 他会自动呈现浏览器的登录界面.
文字分享:
Objective-C:
[[RTumblrManager shared] shareText: text title: title webpageURL: webpageURL from: context completion: completion];
Swift:
RTumblrManager.shared.share(text: text, title: title, webpageURL: webpageURL, from: context, completion: completion)
表现:
图片链接分享:
Objective-C:
[[RTumblrManager shared] shareImageWithURL: targetImageURL description: description webpageURL: webpageURL from: context completion: completion];
Swift:
RTumblrManager.shared.share(imageURL: targetImageURL, description: description, webpageURL: webpageURL, from: context, completion: completion)
表现:
准备
分享需要注册平台, Pinterest 开发者主页, 注册应用主页, Pinterest SDK 支持 pod 集成, 接口调用说明.
集成
a. pod 集成: pod “PinterestSDK”, :git => “[email protected]:pinterest/ios-pdk.git”
d. 在 info.plist
文件的 CFBundleURLTypes
中添加:
CFBundleURLTypes
CFBundleURLName
CFBundleURLSchemes
pdkYOURAPPID
e. 添加以下至白名单:
pinterestsdk.v1
b. Swift 语言集成需要 Objective-C - Swift 桥接文件.
接口调用及内部实现
a. 初始化 SDK
Objective-C:
[[RPinterestManager shared] sdkInitializeByAppID: yourAppID appSecret:yourAppSecret];
Swift:
RPinterestManager.shared.sdkInitialize(appID: yourAppID, appSecret: yourAppSecret)
仅做分享功能的话,
secret
字段无用.
b. 分享
⚠️: Pinterest 分享要求项目的 CFBundleDisplayName 一定不能为空!!!
图片链接分享:
Objective-C:
[[RPinterestManager shared] shareImageWithURL: targetImageURL webpageURL: webpageURL onBoard:boardName description: description from: context completion:completion];
Swift:
RPinterestManager.shared.share(imageURL: targetImageURL, webpageURL: webpageURL, boardName: boardName, description: description, from: context, completion: completion)
boardName
字段即使随便设置也不影响, 考虑到有可能对 Pinterest 功能细化的时候会用到这个字段就保留下来了.
表现:
c. 返回本应用
Objective-C:
[[RPinterestManager shared] application:app openURL:url options:nil];
Swift:
RPinterestManager.application(app, open: url, options : options)
Line
准备
分享无需注册平台.
配置
在info.plist
文件中:
添加以下至白名单:
line
接口调用及内部实现
分享
Line 分享是通过 Custom URL Scheme 来打开 Line 客户端进行分享, 但 demo 中实际的方法和 Line 提供的 Custom URL.
文本分享的 URL 为 line://msg/text/?targetText
, 要对 targetText
中的中文、特殊字符等进行处理:
Object-C:
[targetText stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
Swift:
targetText.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
图片分享的 URL 为 line://msg/image/
, URL 后面的部分可通过 UIPasteboard 实例的 name
属性拼接:
Objective-C:
UIPasteboard* p = [UIPasteboard generalPasteboard];
[p setData:(UIImageJPEGRepresentation(image, 1)) forPasteboardType:@"public.jpeg"];
NSURL* lineURL = [NSURL URLWithString:[NSString stringWithFormat:@"line://msg/image/%@",p.name]];
Swift:
let p = UIPasteboard.general
p.setData(UIImageJPEGRepresentation(image, 0.1)!, forPasteboardType:"public.jpeg")
let lineURL = URL(string: String(format: lineURLPrefix + "line://msg/image/%@", p.name as CVarArg))
文字分享:
Objective-C:
[[RLineManager shared] shareText: text];
Swift:
RLineManager.shared.share(text: text)
表现:
图片分享:
Objective-C:
[[RLineManager shared] shareImage: targetImage];
Swift:
RLineManager.shared.share(image: targetImage)
表现:
准备
分享无需注册平台.
配置
在info.plist
文件中:
添加以下至白名单:
whatsapp
接口调用及内部实现
分享
通过 Custom URL Scheme 分享文字, 图片是通过 UIDocumentInteractionController
来实现应用间数据共享, 构建文字的 URL 为 whatsapp://send?text=targetText
文字分享:
Objective-C:
[[RWhatsAppManager shared]shareText: text]
Swift:
RWhatsAppManager.shared.share(text: text)
表现:
图片分享:
Objective-C:
[[RWhatsAppManager shared]shareImage: targetImage from: context];
Swift:
RWhatsAppManager.shared.share(image: targetImage , from: context)
表现:
GooglePlus
准备
分享无需注册平台, Google Plus 开发者主页已经把 iOS 相关移除了.
接口调用及内部实现
分享
Google Plus 只支持通过 Custom URL Scheme 分享网页, 构建 URL 为 https://plus.google.com/share
内部构建:
Objective-C:
NSURLComponents* urlComponents = [[NSURLComponents alloc]
initWithString:@"https://plus.google.com/share"];
urlComponents.queryItems = @[[[NSURLQueryItem alloc]
initWithName:@"url"
value:[shareURL absoluteString]]];
NSURL* url = [urlComponents URL];
if ([SFSafariViewController class]) {
SFSafariViewController* controller = [[SFSafariViewController alloc] initWithURL:url];
controller.delegate = self;
[from presentViewController:controller animated:YES completion:nil];
} else {
[[UIApplication sharedApplication] openURL:url];
}
Swfit:
var components = URLComponents(string: "https://plus.google.com/share")
components?.queryItems = [URLQueryItem(name: "url", value: webpageURL.absoluteString)]
let url = components?.url
if #available(iOS 9, *) {
let vc = SFSafariViewController(url: url!)
vc.delegate = self
from.present(vc, animated: true, completion: nil)
} else {
UIApplication.shared.openURL(url!)
}
网页分享:
Objective-C:
[[RGooglePlusManager shared]shareURL:[NSURL URLWithString: targetURL] from: context];
Swift:
RGooglePlusManager.shared.share(webpageURL: URL(string: targetURL)!, from: context)
表现:
统一分享接口
缺陷
缺陷说在前面, 其实本来不打算统一接口的.
- 假如只想分享某五个平台, 其余的六个平台仍然不可以删掉, 主分享 Manager 和子平台分享 Manager 存在耦和;
- 分享接口优化受限制, 由于前面的平台分享对比表格可知, 国外的平台分享很多都没有回调, 而国内的平台分享内容又存在多种形式, 无法实现高度统一;
- 添加平台没有做去重处理, 造成不必要的开销;
- 分享完毕返回到本应用的统一处理中子平台分享 Manager 和主分享 Manager 存在代码污染.
类图
- RShareManger: 主分享 Manager, 子平台 Manager 的初始化、分享、应用跳转和一些其他操作都在此进行;
- RPlatform: 主要进行应用是否安装、添加目标应用的操作;
- RRegister: 主要进行
RShareManager
和子平台分享 Manager 的 SDK 初始化衔接; - RImageContent、RVideoContent、RTextContent、RWebpageContent 为四种对应分享内容模型.
详细设计
**a. 平台添加 **
平台相关都交给 RPlatform
去处理, 平台的添加借鉴了 Java 中的 Builder 模式思路去处理, RPlatform
的成员属性 targets
在 Objective-C 中为:
@property (strong, nonatomic, readonly) NSArray* targets;
Swift 中为:
var targets : Array = [] // 多态的体现
add
函数为添加平台的操作, 参数为平台枚举 RShareSDKPlatform
, RPlatform
的私有成员属性 info
为字典类型, key 为平台的字符串形式, value 平台类型 , 通过 add
操作的平台枚举去取出 info
中对应的平台类型添加到 targets
中.
b. 分享频道
以 Objective-C 为例, 在 RShareManager
定义了分享通道枚举:
typedef NS_ENUM(NSInteger, RShareChannel) {
RShareChannelQQSession, // QQ 好友
RShareChannelQQFavorite, // QQ 收藏
RShareChannelQQDataLine, // QQ 我的电脑(数据传输)
RShareChannelQZone, // QQ 空间
RShareChannelWechatSession, // 微信好友
RShareChannelWechatFavorite, // 微信收藏
RShareChannelWechatTimeline, // 微信朋友圈
RShareChannelFacebookClient, // Facebook 客户端
RShareChannelFacebookBroswer, // Facebook Feed 形式网页
RShareChannelTwitter,// 推特
RShareChannelSinaWeibo, // 新浪微博
RShareChannelSinaWeiboStory, // 新浪微博 - 我的故事
RShareChannelLine, // Line
RShareChannelInstagram, // Instagram
RShareChannelTumblr, // Tumblr
RShareChannelPinterest, // Pinterest
RShareChannelGooglePlus, // GooglePlus
RShareChannelWhatsApp // WhatsApp
};
c. 初始化以及注册平台
由 ShareSDK iOS 版激发灵感进行构建.
RShareManager
通过单例创建, 实例函数 registerPlatforms:
为注册实例化子平台 Manager 的过程, Objective-C 中通过 runtime
实现:
// code snippet ...
@autoreleasepool {
Class cls = p.targets[i];
id obj = objc_msgSend(objc_msgSend(cls, @selector(alloc)), @selector(init));
SEL sel = @selector(connect:);
((void(*)(id,SEL, RConfiguration))objc_msgSend)(obj, sel, c);
}
Swift 中暂时没找到类似的方法, 采用了原始的 switch-case
逐个判断并初始化.
其中 RConfiguration
为:
Objective-C:
// 定义在 RShare.h 中
typedef void (^RConfiguration)(RShareSDKPlatform platform, RRegister* obj);
Swift:
// 定义在 RShareManager 中
typealias RConfiguration = (_ paltform : RShareSDKPlatform,_ obj : RRegister) -> Void
每个子平台 Manager 都有 connect
函数, 参数是 RConfiguration
类型, 返回平台信息是因为不是所有的平台都需要初始化 SDK, 返回 RRegister
实例的目的是把实例化的工作交给 RRegister
去做.
RRegister
内部逻辑很简单, 只有初始化三方平台 SDK 的工作.
d. 返回本应用
Objective-C 中通过 runtime
实现:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options {
SEL sel = @selector(application:openURL:options:);
id obj = objc_msgSend(objc_msgSend(_cls, @selector(alloc)), @selector(init));
return ((BOOL(*)(id,SEL,id,id,id))objc_msgSend)(obj, sel, application,url,options);
}
其中 _cls
是在分享的时候通过分享接口中 channel
字段通过 -(Class)getCls:(RShareChannel)channel
确定, objCls
在 Swift 中通过同样的方法获得: func getSubCls(channel : RShareChannel) -> RShare.Type
.
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return objCls.application(app, open: url, options : options)
}
接口
添加平台及初始化需要注册的平台:
Objective-C:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
RPlatform* p = [RPlatform make:^(PlatformBuilder *builder) {
[builder add:RShareSDKPinterest];
[builder add:RShareSDKWhatsApp];
[builder add:RShareSDKWechat];
[builder add:RShareSDKSina];
[builder add:RShareSDKQQ];
[builder add:RShareSDKTumblr];
[builder add:RShareSDKFacebook];
[builder add:RShareSDKTwitter];
[builder add:RShareSDKLine];
[builder add:RShareSDKGooglePlus];
[builder add:RShareSDKInstagram];
}];
[[RShareManager shared] registerPlatforms:p onConfiguration:^(RShareSDKPlatform platform, RRegister *obj) {
switch (platform) {
case RShareSDKPinterest:
[obj connectPinterestByAppID: yourAppID appSecret: nil];
break;
case RShareSDKQQ:
[obj connectQQByAppID:yourAppID appKey: yourKey];
break;
case RShareSDKSina:
[obj connectSinaWeiboByAppKey: yourKey appSecret:yourSecret];
break;
case RShareSDKWechat:
[obj connectWechatByAppID: yourAppID appSecret:yourSecret];
break;
case RShareSDKTumblr:
[obj conncetTumblrByConsumerKey: yourKey consumerSecret: yourSecret];
break;
case RShareSDKFacebook:
[obj connectFacebookByID:yourAppID secret:nil];
break;
case RShareSDKTwitter:
[obj connectTwitterByConsumerKey:yourKey consumerSecret:yourSecret];
default:
break;
}
}];
return YES;
}
Swift:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let platform = RPlatform.make { (builder) in
builder.add(p: .Facebook)
builder.add(p: .Twitter)
builder.add(p: .QQ)
builder.add(p: .Wechat)
builder.add(p: .Instagram)
builder.add(p: .Tumblr)
builder.add(p: .Pinterest)
builder.add(p: .Sina)
builder.add(p: .GooglePlus)
builder.add(p: .Line)
builder.add(p: .WhatsApp)
}
RShareManager.shared.registerPlatform(platform: platform) { (p, obj) in
switch p {
case .Facebook:
obj.connectFacebook(appID: yourAppID, secret: nil)
case .Pinterest:
obj.connectPinterest(appID: yourAppID, secret: nil)
case .QQ:
obj.connectQQ(appID: yourAppID, key: yourKey)
case .Sina:
obj.connectSinaWeibo(appKey: yourKey, secret: yourSecret)
case .Wechat:
obj.connectWechat(appID: yourAppID, secret: yourSecret)
case .Tumblr:
obj.connectTumblr(consumerKey: yourKey, secret: yourSecret)
case .Twitter:
obj.connectTwitter(consumerKey: yourKey, secret: yourSecret)
default : break
}
}
return true
}
构建分享模型:
以 RImageContent
为例:
Objective-C:
RImageContent* content = RImageContent make:^(RImageContentBuilder *builder) {
// ...
}
Swift:
RImageContent.make { (builder) in
// ...
}
分享:
以分享 RImageContent
为例:
Objective-C:
[RShareManager shared] shareImageWithContent:content channel: channel from: context completion:^(RShareSDKPlatform platform, ShareResult result, NSString * _Nullable errorInfo) {
// ...
}
Swift:
RShareManager.shared.shareImage(content: content, channel: channel, from: context) { (platform, result, errorInfo in
// ...
}
返回本应用:
Objective-C:
[[RShareManager shared]application:app openURL:url options:options];
Swift:
RShareManager.shared.application(app, open: url, options : options)
源码
Objective-C 版本源码、 Swift 版本源码.
无关
个人博客, 还在学习中, 请多指教.