前置步骤

在接入openSDK之前,我们需要做几个前置步骤:

首先需要去Apple开发者账号中配置Universal Link,这是为了手机中如果安装了支持该链接的App就会直接进入到App中;如果没有安装APP则会跳转到Safari浏览器中,展示H5页面。 这样可以通过HTTPS链接来无缝启动APP。

在微信开放平台创建一个移动应用,创建的时候需要用到上面的Universal Link。

创建完成后,开通微信登录及分享功能。

应用详情中查看你的Universal Link、Bundle id、AppID、AppSecret,后续需要使用。

apple-app-site-association记录下来(可以通过 https://your_UniversalLink/apple-app-site-association 来查看你的配置)

微信openSDK引用

我们可以使用CocoaPods来引用微信的sdk并加以配置,具体步骤如下:

在项目下pod init生成Podfile文件,添加pod ‘WechatOpenSDK’,然后pod install

打开项目,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序 id。

选中“TARGETS”一栏,在“Signing&Capabilities”下面,点击 +Capability,打开Associated Domains开关,将Universal Links域名加到配置上。

在info.plst中添加LSApplicationQueriesSchemes,LSApplicationQueriesSchemes 类型选array,添加item0 value为weixin,添加item1,value为weixinULAPI

微信sdk中oc桥接swift

因为微信sdk为oc的代码,这里我们通过桥接Bridging_Header来将代码import进去,具体步骤如下:

新建HeaderFile文件,添加import:

1
2
3
4
5
6
7
8
9
#ifndef WeChatLoginDemo_Bridging_Header_h
#define WeChatLoginDemo_Bridging_Header_h

#import "WXApi.h"
#import "WXApiObject.h"
#import "WechatAuthSDK.h"
#import "WebKit/WebKit.h"

#endif /* WeChatLoginDemo_Bridging_Header_h */

选中“TARGETS”一栏,在“Build Settings”下面Objective-C Bridging Header下面把新建的HeaderFile路径配上去。
调用微信openSDK完成登录和分享功能
我们要完成该功能,需要:

在代码中向微信终端注册你的 id
实现 WXApiDelegate 协议的两个方法 onReq 和 onResp
重写 AppDelegate 和 openURL 方法
最后调用 WXApi 的 sendReq 函数
拿到微信返回的code,通过微信接口来拿access_token,再通过access_token拿具体信息,更新界面
不要忘记将之前配置的apple-app-site-association的json文件加入你的项目(可以通过 https://your_UniversalLink/apple-app-site-association 来查看你的配置)
具体代码如下:

因为Swiftui没有Appdelegate,所以我们自己新建一个Appdelegate,实现WXApiDelegate协议的两个方法,并在初始化时注册id:

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
import Foundation
import UIKit

class AppDelegate: NSObject, UIApplicationDelegate , WXApiDelegate, WXApiLogDelegate{
func onLog(_ log: String, logLevel level: WXLogLevel) {
print(log)
}

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

WXApi.startLog(by: WXLogLevel.detail, logDelegate: self)
//需要用到微信开放平台注册移动应用的AppID和universalLink,然后注册id
let isReg = WXApi.registerApp(Utiliy.AppID, universalLink: "https://xxx")
print("注册:\(isReg)")

return isReg
}

func onReq(_ req: BaseReq) {
//微信终端向第三方程序发起请求,要求第三方程序响应。第三方程序响应完后必须调用 sendRsp 返回。在调用 sendRsp 返回时,会切回到微信终端程序界面。
}

func onResp(_ resp: BaseResp) {
//如果第三方程序向微信发送了sendReq的请求,那么onResp会被回调。sendReq请求调用后,会切到微信终端程序界面。
//微信返回的code
if resp.isKind(of: SendAuthResp.self){
let arsp = resp as! SendAuthResp
if !(arsp.code?.isEmpty ?? true) {
NotificationCenter.default.post(name: Notification.Name("code"), object: arsp.code)
}
}
}

deinit {
NotificationCenter.default.removeObserver(self)
}

}

在view入口处调用onOpenURL接口,并Adaptor你的AppDelegate,这样就能够初始化时调用AppDelegate:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import SwiftUI

@main
struct WeChatLoginDemoApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

var body: some Scene {
WindowGroup {
ContentView()

.onOpenURL{url in
WXApi.handleOpen(url, delegate: appDelegate)
}
}
}
}

然后就拿到微信code后,通过微信api拿access_token和登录信息,分享就直接调用send方法就行:

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import SwiftUI

struct ContentView: View {
@ObservedObject var model: Model = Model()

var urlString: String = ""
@ObservedObject var imageLoader = ImageLoader()
@State var image: UIImage = UIImage()

//onResp拿到code后的通知界面
let pub = NotificationCenter.default
.publisher(for: NSNotification.Name("code"))

var body: some View {
VStack(alignment: .leading, spacing: 20){
Text("openid: \(model.openid)")
.padding()
Text("nickname: \(model.nickname)")
.padding()
Text("sex: \(model.sex) (1 为男性,2 为女性, 0为空)")
.padding()
Text("province: \(model.province)")
.padding()
Text("city: \(model.city)")
.padding()
Text("country: \(model.country)")
.padding()
Text("unionid: \(model.unionid)")
.padding()

Image(uiImage: image)
.resizable()
.frame(width: 64, height: 64, alignment: .center)
.onReceive(imageLoader.$data) { data in
guard let data = data else { return }
self.image = UIImage(data: data) ?? UIImage()
}

Button("微信登录信息", action: {
getCode()
}).padding()

Button("微信分享信息", action: {
sendText(text: "test", inScene: WXSceneSession)
}).padding()
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
.onReceive(pub) { (output) in
//code拿access_token
let code = output.object as! String
self.getInfo(code: code)
}

}

func getInfo(code: String){
let urlString = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=\(Utiliy.AppID)&secret=\(Utiliy.AppSecret)&code=\(code)&grant_type=authorization_code"
var request = URLRequest(url: URL(string: urlString)!)
request.httpMethod = "GET"

URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
if error == nil && data != nil {
do {
let dic = try JSONSerialization.jsonObject(with: data!, options: []) as! [String: Any]
let access_token = dic["access_token"] as! String
let openID = dic["openid"] as! String
//通过access_token拿微信登录信息
requestUserInfo(access_token, openID)
} catch {
print(#function)
}
return
}
})
}.resume()
}

func requestUserInfo(_ token: String, _ openID: String) {
let urlString = "https://api.weixin.qq.com/sns/userinfo?access_token=\(token)&openid=\(openID)"

var request = URLRequest(url: URL(string: urlString)!)
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
if error == nil && data != nil {
do {
let dic = try JSONSerialization.jsonObject(with: data!, options: []) as! [String: Any]
self.model.openid = dic["openid"] as! String
self.model.nickname = dic["nickname"] as! String
self.model.sex = dic["sex"] as! Int
self.model.province = dic["province"] as! String
self.model.city = dic["city"] as! String
self.model.country = dic["country"] as! String
self.model.headimgurl = dic["headimgurl"] as! String
self.model.unionid = dic["unionid"] as! String
imageLoader.loadData(from: self.model.headimgurl)
} catch {
print(#function)
}
return
}
})
}.resume()
}

//发送信息
func sendText(text:String, inScene: WXScene){
let req = SendMessageToWXReq()
req.text=text
req.bText=true
req.scene=Int32(inScene.rawValue)
WXApi.send(req)
}

//调用微信登录
func getCode(){
let req = SendAuthReq()
req.scope = "snsapi_userinfo"
req.state = "wx_oauth_authorization_state"
DispatchQueue.main.async{
WXApi.send(req,completion: nil)
}
}
}