Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SwiftUI-调用微信openSDK登录及分享 #81

Open
djk3000 opened this issue Jun 12, 2022 · 1 comment
Open

SwiftUI-调用微信openSDK登录及分享 #81

djk3000 opened this issue Jun 12, 2022 · 1 comment

Comments

@djk3000
Copy link
Owner

djk3000 commented Jun 12, 2022

前置步骤

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

  1. 首先需要去Apple开发者账号中配置Universal Link,这是为了手机中如果安装了支持该链接的App就会直接进入到App中;如果没有安装APP则会跳转到Safari浏览器中,展示H5页面。 这样可以通过HTTPS链接来无缝启动APP。
  2. 微信开放平台创建一个移动应用,创建的时候需要用到上面的Universal Link。
  3. 创建完成后,开通微信登录及分享功能。
  4. 应用详情中查看你的Universal Link、Bundle id、AppID、AppSecret,后续需要使用。
  5. apple-app-site-association记录下来(可以通过https://(Universal Link)/apple-app-site-association来查看你的配置)

微信openSDK引用

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

  1. 在项目下pod init生成Podfile文件,添加pod 'WechatOpenSDK',然后pod install
  2. 打开项目,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序 id。
  3. 选中“TARGETS”一栏,在“Signing&Capabilities”下面,点击 +Capability,打开Associated Domains开关,将Universal Links域名加到配置上。
  4. 在info.plst中添加LSApplicationQueriesSchemes,LSApplicationQueriesSchemes 类型选array,添加item0 value为weixin,添加item1,value为weixinULAPI

微信sdk中oc桥接swift

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

  1. 新建HeaderFile文件,添加import:
#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 */
  1. 选中“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://Universal Link/apple-app-site-association来查看你的配置)

具体代码如下:

  1. 因为Swiftui没有Appdelegate,所以我们自己新建一个Appdelegate,实现WXApiDelegate协议的两个方法,并在初始化时注册id:
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)
    }
}
  1. 在view入口处调用onOpenURL接口,并Adaptor你的AppDelegate,这样就能够初始化时调用AppDelegate:
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)
                }
        }
    }
}
  1. 然后就拿到微信code后,通过微信api拿access_token和登录信息,分享就直接调用send方法就行:
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)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

参考文档


@haveagoodday-github
Copy link

太棒啦!!!完美解决!!!谢谢你

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants