目录
- 先看一下demo演示
- 安装pod 安装
- 到微信官网注册账户,并获取3个数据
- 添加关联域名 Associated Domains
- info.plist里面 添加 白名单
- 添加 URL Schemes
- AppDelegate.swift文件中设置 方法:
- oc AppDelegate.m文件中方法使用,oc的例子中没有使用storyboard,而是直接启动VC1.xib
- 把后台设置的3个数据添加进全局变量伪装成oc的宏定义给封装的类用
- 添加自定义的微信管理工具类TdwWeChatLoginManager
- 添加桥接文件
- swift页面调用微信登录并且获取返回值
- oc页面调用微信登录并且获取返回值
- demo中的点击按钮
- swift demo下载
微信官网的登录demo下载以后运行没跑起来,看文档又说的不全,自己做了demo并且封装成了swift和oc都能调用的工具类,demo放在最后
注意,能复制的地方坚决不要手动输入拼写,我之前自己手动拼写了白名单,结果就错了,找了半天才发现拼写错误,需要复制的地方请直接复制粘贴,我文章最下面的demo里的文本
先看一下demo演示
安装pod 安装
创建podfile文件,里面添加:pod ‘WechatOpenSDK’
默认安装的是新版的WechatOpenSDK (1.8.7.1)
终端执行pod install,安装完以后打开 项目名.xcworkspace文件
到微信官网注册账户,并获取3个数据
-
账户后台的3个数据:
- app ID
- universal link
- app Secret
并且获取3个值,如果你没有,只是想试验一下,可以使用我例子里面已经注册号的3个值
添加关联域名 Associated Domains
点击项目名 targets 选择 Signing & Capabilities ->Capability ->Associated Domains ,点击加好 添加域名,以applinks: 开头后面tian’ji universal link里面的值
info.plist里面 添加 白名单
白名单的key叫:LSApplicationQueriesSchemes
把 info.plist 右键点击 open as-> source code 复制下面的添加到最下面倒数第3行的上面,
LSApplicationQueriesSchemes
weixin
weixinULAPI
wechat
或者手动info.plist open as ->Property List,复制我demo里面的info.plist 手动粘贴进去,建议复制,手动粘贴容易出错
添加 URL Schemes
target -> info -> URL Types 点击下面+加号, 添加 URL Schemes ,填写内容是 微信后台注册的app ID,如下图所示
AppDelegate.swift文件中设置 方法:
唯一要说的是:下面有一个巨大的坑:就是 WXApi.handleOpen(url, delegate: self)这个方法这个方法是oc的+ (BOOL)handleOpenURL:(NSURL *)url delegate:(nullable id)delegate; 方法,在系统自动转换为swift代码的时候会直接转换为WXApi.handleOpen( url, delegate: self,),编译报错提示错误找不到函数上下文,意思是找不到这个函数,当时我解决的方法是放到方法用oc类调用oc的handleOpenURL:(NSURL *)url ,然后再用swift调用oc的类方法, 最终我的解决方法是,先把在swift里面写下面的代码,系统会提示函数名字已经改了,然后点击fix修复,系统会帮我修复成handleOpen方法,再编译,就不提示handleOpen找不到了,这个是swift系统bug
直接粘贴下面代码就行
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
WXApi.registerApp(WXAPP_ID, universalLink: UNIVERSAL_LINK)
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
if url.host == "oauth"{//微信登录
return WXApi.handleOpen(url, delegate: self) //如果handleOpen提示错误,就先用oc原来的方法return WXApi.handleOpenURL(url, delegate: self),然后让系统自动提示rename,这样就能编译通过
}
return true
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return WXApi.handleOpen(url, delegate: self)
}
}
extension AppDelegate:WXApiDelegate{
func onReq(_ req: BaseReq) {
//onReq是微信终端向第三方程序发起请求,要求第三方程序响应。第三方程序响应完后必须调用sendRsp返回。在调用sendRsp返回时,会切回到微信终端程序界面。
print(req.type)
}
func onResp(_ resp: BaseResp) {
//如果第三方程序向微信发送了sendReq的请求,那么onResp会被回调。sendReq请求调用后,会切到微信终端程序界面。
if resp.isKind(of: SendAuthResp.self) {
let response = resp as! SendAuthResp
print("ErrCode : (response.errCode)")
print("EodeStr : (response.errStr)")
print("Code : (response.code)")
print("State : (response.state)")
print("Lang : (response.lang)")
print("Country : (response.country)")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "WXLoginSuccessNotification"), object: response.code)
}
}
}
oc AppDelegate.m文件中方法使用,oc的例子中没有使用storyboard,而是直接启动VC1.xib
AppDelegate.m内容
//
// AppDelegate.m
// wechatLoginOCDemo
//
// Created by tdw on 2021/3/5.
//
#import "AppDelegate.h"
#import <WXApi.h>
#import <WXApiObject.h>
#import "VC1.h"
@interface AppDelegate ()<WXApiDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[WXApi registerApp:WXAPP_ID universalLink:UNIVERSAL_LINK];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
VC1 *root = [[VC1 alloc] initWithNibName:@"VC1" bundle:nil]; //加载nib文件,生成View实例
[self.window setRootViewController:root]; //将new出来的view实例设置为window的root view。
[self.window makeKeyAndVisible]; //将当前winsow置为当前状态下的key window,并呈现出来。Makes the receiver the key window and visible.
return YES;
return YES;
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
if ([url.host isEqualToString:@"oauth"]){
return [WXApi handleOpenURL:url delegate:self];
}
return false;
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
return [WXApi handleOpenURL:url delegate:self];
}
- (void)onReq:(BaseReq *)req{
NSLog(@"req=%@",req);
}
- (void)onResp:(BaseResp *)resp{
if([resp isKindOfClass:[SendAuthResp class]]){
SendAuthResp *resp2 = (SendAuthResp *)resp;
[[NSNotificationCenter defaultCenter] postNotificationName:NotiWxLoginSuucess object:resp2.code];
}else{
NSLog(@"授权失败");
}
}
@end
把后台设置的3个数据添加进全局变量伪装成oc的宏定义给封装的类用
在swift项目中,添加一个用来存储全局变量的文件 common.swift
//
// common.swift
// wechatLoginDemo
//
// Created by tdw on 2021/3/4.
// Copyright © 2021 谭迪文. All rights reserved.
//
let WXAPP_ID = "wxf1dffab76327aeb6"
let UNIVERSAL_LINK = "https://tmx.zwfw.gswuwei.gov.cn/"
let WX_APPSecret = "648a9644e08eeac108b6b0572e00978e"
let NotiWxLoginSuucess = "NotiWxLoginSuucess"//定义一个微信登录成功以后回调发送的通知
oc项目定义宏定义
在oc中我添加了一个PrefixHeader.pch预处理文件,项目中所有文件都包含他
预处理文件是包含了3个 微信后台设置的数据,和一个自定义通知的宏定义NotiWxLoginSuucess
//
// PrefixHeader.pch
// wechatLoginOCDemo
//
// Created by tdw on 2021/3/5.
//
#ifndef PrefixHeader_pch
#define PrefixHeader_pch
// Include any system framework and library headers here that should be included in all compilation units.
// You will also need to set the Prefix Header build setting of one or more of your targets to reference this file.
#define WXAPP_ID @"wxf1dffab76327aeb6"
#define UNIVERSAL_LINK @"https://tmx.zwfw.gswuwei.gov.cn/"
#define WX_APPSecret @"648a9644e08eeac108b6b0572e00978e"
#define NotiWxLoginSuucess @"NotiWxLoginSuucess"//定义一个微信登录成功以后回调发送的通知
#endif /* PrefixHeader_pch */
添加自定义的微信管理工具类TdwWeChatLoginManager
这个工具类,swift和 oc 项目都要添加,这个支持双语言调用,里面用的到这个 字符串NotiWxLoginSuucess在上面定义了
//
// TdwWeChatLoginManager.swift
// wechatLoginDemo
//
// Created by tdw on 2021/3/4.
// Copyright © 2021 谭迪文. All rights reserved.
//
import UIKit
//微信的登录类
@objc class TdwWeChatLoginManager: NSObject {
@objc static var shared:TdwWeChatLoginManager = {
return TdwWeChatLoginManager()
}()
typealias CallBack = ([String:Any])->Void
var loginAfter:CallBack = { _ in }
private override init() {
//添加通知监听
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(WXLoginSuccess(notification:)), name: NSNotification.Name(rawValue: NotiWxLoginSuucess), object: nil)
}
@objc func login( loginAfter:@escaping CallBack) {
// 微信登录请求
let urlStr = "weixin://"
if UIApplication.shared.canOpenURL(URL.init(string: urlStr)!) {
let red = SendAuthReq.init()
red.scope = "snsapi_message,snsapi_userinfo,snsapi_friend,snsapi_contact"
red.state = "wechat_sdk_demo"
WXApi.send(red)
}else{
if #available(iOS 10.0, *) {
//qUQVDfDEVK0rrbRu9xG7这个数值可以自己随意修改
UIApplication.shared.open(URL.init(string: "http://weixin.qq.com/r/qUQVDfDEVK0rrbRu9xG7")!, options: [:], completionHandler: nil)
} else {
// Fallback on earlier versions
UIApplication.shared.openURL(URL.init(string: "http://weixin.qq.com/r/qUQVDfDEVK0rrbRu9xG7")!)
}
}
self.loginAfter = loginAfter
}
deinit {
NotificationCenter.default.removeObserver(self)
}
/** 微信通知 */
@objc func WXLoginSuccess(notification:Notification) {
let code = notification.object as! String
// let requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=\(WXAPP_ID)&secret=\(WX_APPSecret)&code=\(code)&grant_type=authorization_code"
let APPSecret = WX_APPSecret
let requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=\(WXAPP_ID)&secret=\(APPSecret)&code=\(code)&grant_type=authorization_code"
DispatchQueue.global().async {
let requestURL: URL = URL.init(string: requestUrl)!
let data = try? Data.init(contentsOf: requestURL, options: Data.ReadingOptions())
DispatchQueue.main.async {
let jsonResult = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String,Any>
let openid: String = jsonResult["openid"] as! String
let access_token: String = jsonResult["access_token"] as! String
self.getUserInfo(openid: openid, access_token: access_token)
}
}
}
/** 获取用户信息 */
func getUserInfo(openid:String,access_token:String) {
let requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=\(access_token)&openid=\(openid)"
DispatchQueue.global().async {
let requestURL: URL = URL.init(string: requestUrl)!
let data = try? Data.init(contentsOf: requestURL, options: Data.ReadingOptions())
DispatchQueue.main.async {
[unowned self] in
let jsonResult = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String,Any>
self.loginAfter(jsonResult)
}
}
}
}
添加桥接文件
oc
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import <WXApi.h>
#import <WXApiObject.h>
#import "yyModel.h"
#import "UIImageView+WebCache.h"
#import "PrefixHeader.pch"
swift
#import <WXApi.h>
#import <WXApiObject.h>
#import "VC1.h"
#import "yyModel.h"
#import "UIImageView+WebCache.h"
swift页面调用微信登录并且获取返回值
// 微信登录请求
TdwWeChatLoginManager.shared.login { (jsons) in
print("返回结果jsons=",jsons)
}
获得返回打印结果,里面包含头像的图片地址,昵称,性别城市,省份,国家等信息:
返回结果jsons= [“unionid”: ou4DdsiJTIo_LaxQZvKDpCKeKjI4, “nickname”: 正义, “sex”: 1, “province”: Heilongjiang, “headimgurl”: https://thirdwx.qlogo.cn/mmopen/vi_32/Ylib33UuwG3SEpLkArOlI3yDKSSvVQPQAAbGDFCKqvrO75jUHn7gHrN3BfRzkOdQkfs2IvpK7Y0mOv6PHPAkZsg/132, “city”: Harbin, “language”: zh_CN, “privilege”: <__NSArrayM 0x283bb6070>(
)
, “country”: CN, “openid”: o-C4n1NbW1Me6CUXieAFxQmVJQMM]
oc页面调用微信登录并且获取返回值
[[TdwWeChatLoginManager shared] loginWithLoginAfter:^(NSDictionary<NSString *,id> * _Nonnull jsons) {
NSLog(@"OC控制器jsons=%@",jsons);
}];
我在demo例子中添加了把返回值赋值到页面效果如最上面的演示图gif
demo中的点击按钮
@IBAction func btnLoginClick(_ sender: Any) {
// 微信登录请求
TdwWeChatLoginManager.shared.login { [unowned self] (jsons) in
print("===============================================================")
print("返回结果jsons=",jsons)
let item = WeChatLoginItem.yy_model(with: jsons)
self.item = item
if let urlStr = item?.headimgurl, let url = URL(string: urlStr) {
self.imageV.sd_setImage(with:url, placeholderImage: UIImage(named: "questionmark.folder"), options: [], context: nil)
}
}
}
注意,如果例子运行不了,请把证书选择自己的真机证书,用真机运行