NBus 之 WeiboSDKHandler

微博 SDK 的接入不难,本 Handler 基于微博 SDK 3.2.7 实现。


General

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class WeiboSDKHandler {

public let endpoints: [Endpoint] = [
Endpoints.Weibo.timeline,
]

public let platform: Platform = Platforms.weibo

public var isInstalled: Bool {
WeiboSDK.isWeiboAppInstalled()
}

private var shareCompletionHandler: Bus.ShareCompletionHandler?
private var oauthCompletionHandler: Bus.OauthCompletionHandler?

public let appID: String
private let redirectLink: URL

public var logHandler: Bus.LogHandler = { message, _, _, _ in
#if DEBUG
print(message)
#endif
}

private var helper: Helper!

public init(appID: String, redirectLink: URL) {
self.appID = appID
self.redirectLink = redirectLink

helper = Helper(master: self)

#if DEBUG
WeiboSDK.enableDebugMode(true)
#endif

WeiboSDK.registerApp(
appID.trimmingCharacters(in: .letters)
)
}
}

调用 WeiboSDK.registerApp(_:) 注册微博 SDK,调用 WeiboSDK.enableDebugMode(_:) 记录日志。Helper 处理微博的回调,相关内容下文会进行说明。

LogHandlerProxyType

1
extension WeiboSDKHandler: LogHandlerProxyType {}

声明 WeiboSDKHandler 遵循 LogHandlerProxyType 协议。

ShareHandlerType

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
extension WeiboSDKHandler: ShareHandlerType {

public func share(
message: MessageType,
to endpoint: Endpoint,
options: [Bus.ShareOptionKey: Any] = [:],
completionHandler: @escaping Bus.ShareCompletionHandler
) {
guard isInstalled else {
completionHandler(.failure(.missingApplication))
return
}

shareCompletionHandler = completionHandler

let request = WBSendMessageToWeiboRequest()
request.message = WBMessageObject()

switch message {
case let message as TextMessage:
request.message.text = message.text

case let message as ImageMessage:
let imageObject = WBImageObject()
imageObject.imageData = message.data

request.message.imageObject = imageObject

case let message as WebPageMessage:
let webPageObject = WBWebpageObject()
webPageObject.webpageUrl = message.link.absoluteString
webPageObject.title = message.title
webPageObject.description = message.description
webPageObject.thumbnailData = message.thumbnail

webPageObject.objectID = UUID().uuidString

request.message.mediaObject = webPageObject

default:
completionHandler(.failure(.unsupportedMessage))
return
}

let result = WeiboSDK.send(request)

if !result {
completionHandler(.failure(.invalidMessage))
}
}
}

在分享流程中:

  1. 调用 isInstalled 判断是否安装微博,没有则提前退出。
  2. 创建 WBSendMessageToWeiboRequest 请求。
  3. 创建 WBMessageObject 多媒体消息。
  4. 判断 message 的具体类型,设置 request.message 的相关属性。注意 WBWebpageObject 需要设置 objectID
  5. 调用 WeiboSDK.send(_:) 拉起微博分享。

OauthHandlerType

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
extension WeiboSDKHandler: OauthHandlerType {

public func oauth(
options: [Bus.OauthOptionKey: Any] = [:],
completionHandler: @escaping Bus.OauthCompletionHandler
) {
guard isInstalled else {
completionHandler(.failure(.missingApplication))
return
}

oauthCompletionHandler = completionHandler

let request = WBAuthorizeRequest()
request.redirectURI = redirectLink.absoluteString

let result = WeiboSDK.send(request)

if !result {
completionHandler(.failure(.unknown))
}
}
}

在登录流程中:

  1. 调用 isInstalled 判断是否安装微博,没有则提前退出。
  2. 创建 WBAuthorizeRequest 请求。
  3. 调用 WeiboSDK.send(_:) 拉起微博登录。

OpenURLHandlerType

1
2
3
4
5
6
extension WeiboSDKHandler: OpenURLHandlerType {

public func openURL(_ url: URL) {
WeiboSDK.handleOpen(url, delegate: helper)
}
}

调用 WeiboSDK.handleOpen(_:delegate:) 处理 URL Scheme 回调。

Helper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
extension WeiboSDKHandler {

fileprivate class Helper: NSObject, WeiboSDKDelegate {

weak var master: WeiboSDKHandler?

required init(master: WeiboSDKHandler) {
self.master = master
}

func didReceiveWeiboRequest(_ request: WBBaseRequest!) {
assertionFailure("\(String(describing: request))")
}

func didReceiveWeiboResponse(_ response: WBBaseResponse!) {
switch response {
case let response as WBSendMessageToWeiboResponse:
switch response.statusCode {
case .success:
master?.shareCompletionHandler?(.success(()))
case .userCancel:
master?.shareCompletionHandler?(.failure(.userCancelled))
default:
master?.shareCompletionHandler?(.failure(.unknown))
}
case let response as WBAuthorizeResponse:
switch (response.statusCode, response.accessToken) {
case let (.success, accessToken):
let parameters = [
OauthInfoKeys.accessToken: accessToken,
]
.compactMapContent()

if !parameters.isEmpty {
master?.oauthCompletionHandler?(.success(parameters))
} else {
master?.oauthCompletionHandler?(.failure(.unknown))
}
case (.userCancel, _):
master?.oauthCompletionHandler?(.failure(.userCancelled))
default:
master?.oauthCompletionHandler?(.failure(.unknown))
}
default:
assertionFailure("\(String(describing: response))")
}
}
}
}

extension WeiboSDKHandler {

public enum OauthInfoKeys {

public static let accessToken = Bus.OauthInfoKey(rawValue: "com.nuomi1.bus.weiboSDKHandler.accessToken")
}
}

创建 Helper 处理微博的回调:

  1. WeiboSDKHandler 强持有 Helper,所以 Helpermaster 声明为 weak 避免循环引用。
  2. 处理分享回调时,返回 WBSendMessageToWeiboResponse,调用 response.statusCode 判断是否为 .success,调用 master?.shareCompletionHandler?(.success(())) 完成分享回调。
  3. 处理登录回调时,返回 WBAuthorizeResponse,调用 response.statusCoderesponse.accessToken 判断成功且 accessToken 不为空时,调用 master?.oauthCompletionHandler?(.success(parameters)) 完成登录回调。

总结

本文通过封装微博 SDK 做出 WeiboSDKHandler,实现微博的登录和分享功能。微博支持的多媒体消息与微博或 QQ 不太一样,因此只实现了以上几个。同时微博 SDK 只能打包到主工程,需要特别注意。

参考

  1. Weibo - ReadMe