一、接入微信第三方登录准备工作。
移动应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。
1. 在微信开放平台注册开发者帐号,并拥有一个已审核通过的移动应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程
注意:
1.审核需要提供一个28*28和108*108的图标
2.审核需要提供Bundle ID
3.审核需要一点时间,我之前一天就审核通过了
2. 下载iOS微信SDK
下载最新的SDK 地址: 点击打开链接
3. 将SDK放到工程目录中
4. 补充导入一些依赖框架:Target - Build Phases - Link Binary With Libraries
5. 添加URL Types:Target - Info - URL Types
6. 添加iOS9 URL Schemes
**注意: 当程序出现以下错误,说明没有针对iOS9 增加白名单。在info.plist文件中加入 LSApplicationQueriesSchemes **
-canOpenURL: failed for URL: "weixin://app/wx9**********dfd30/" - error: "This app is not allowed to query for scheme weixin"
7. iOS9中新增App Transport Security(简称ATS)特性, 主要使到原来请求的时候用到的HTTP,都转向TLS1.2协议进行传输。这也意味着所有的HTTP协议都强制使用了HTTPS协议进行传输。需要在Info.plist新增App Transport Security Settings用于控制ATS的配置:
NSAppTransportSecurity
NSAllowsArbitraryLoads
如果我们在iOS9下直接进行HTTP请求是会收到如下错误提示,需要在Info.plist新增App Transport Security Settings
**App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.**
8. 现在编译应该没有问题
二、代码部分
1. 第一步:在桥接文件中引入"WXApi.h"头文件,然后在中AppDelegate.m写入如下代码:
import UIKit
@UIApplicationMain
// 在Appdelegate里面添加微信代理
class AppDelegate: UIResponder, UIApplicationDelegate, WXApiDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//向微信注册应用
// @param1 微信开发者ID
// @param2 应用附加信息,长度不超过1024字节
WXApi.registerApp("wxed8b3e67969559b5", withDescription: "wechat")
return true
}
// 这个方法是用于从微信返回第三方App 处理微信通过URL启动App时传递的数据
// @param url 微信启动第三方应用时传递过来的URL
// @param delegate WXApiDelegate对象,用来接收微信触发的消息。
func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool {
if url.scheme == "wxed8b3e67969559b5" {
WXApi.handleOpenURL(url, delegate: self)
}
return true
}
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
if url.scheme == "wxed8b3e67969559b5" {
WXApi.handleOpenURL(url, delegate: self)
}
return true
}
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
Tools.logPrint("openURL:\(url.absoluteString)")
if url.scheme == "wxed8b3e67969559b5" {
return WXApi.handleOpenURL(url, delegate: self)
}
return true
}
}
2. 第二步:请求CODE
开发者需要配合使用微信开放平台提供的SDK进行授权登录请求接入。正确接入SDK后并拥有相关授权域(scope,什么是授权域?)权限后,开发者移动应用会在终端本地拉起微信应用进行授权登录,微信用户确认后微信将拉起开发者移动应用,并带上授权临时票据(code)。
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if WXApi.isWXAppInstalled() {
print("weixin ready")
} else {
// 把微信登录的按钮隐藏掉
}
}
// 请求CODE
@IBAction func wechatLoginClick(sender: UIButton) {
// 如果在这里判断是否安装了微信,会报-canOpenURL: failed for URL: "weixin://app/wx5efead4057f98bc0/" - error: "This app is not allowed to query for scheme weixin"错误
let req = SendAuthReq()
req.scope = "snsapi_userinfo"
req.state = "App"
//第三方向微信终端发送一个SendAuthReq消息结构
if !WXApi.sendReq(req) {
print("weixin sendreq failed")
}
}
}
执行完上面那一步后,如果客户端安装了微信,那么就会向微信请求相应的授权,图如下:
返回说明
用户点击授权后,微信客户端会被拉起,跳转至授权界面,用户在该界面点击允许或取消,SDK通过SendAuth的Resp返回数据给调用方。
3. 第三步:通过code获取access_token
获取code后,请求以下链接获取access_token:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&gr
ant_type=authorization_code
// 授权后回调
// AppDelegate.m
func onReq(req: BaseReq!) {
//onReq是微信终端向第三方程序发起请求,要求第三方程序响应。第三方程序响应完后必须调用sendRsp返回。在调用sendRsp返回时,会切回到微信终端程序界面。
print(req.type)
}
func onResp(resp: BaseResp!) {
//如果第三方程序向微信发送了sendReq的请求,那么onResp会被回调。sendReq请求调用后,会切到微信终端程序界面。
if resp.isKindOfClass(SendAuthResp) {
let authResp = resp as! SendAuthResp
print("ErrCode : \(authResp.errCode)") // 0
print("EodeStr : \(authResp.errStr)") // nil
print("Code : \(authResp.code)") // 0017Avci0BJ0Rj1hIqai0jEsci07AvcI
print("State : \(authResp.state)") // State : App
print("Lang : \(authResp.lang)") // nil
print("Country : \(authResp.country)") // nil
if authResp.errCode == 0 {
let code = authResp.code
let AFN = AFHTTPSessionManager()
let params = ["appid": WX_APPID, "secret": WX_APPSECRET_TEST, "code": code, "grant_type": "authorization_code"]
AFN.GET("https://api.weixin.qq.com/sns/oauth2/access_token", parameters: params, success: { (_, response) in
let accessToken = response!["access_token"] as! String
let refreshToken = response!["refresh_token"] as! String
let openID = response!["openid"] as! String
// 本地持久化,以便access_token的使用、刷新或者持续
if (accessToken.isEmpty == false && openID.isEmpty == false) {
NSUserDefaults.standardUserDefaults().setObject(accessToken, forKey: "access_token")
NSUserDefaults.standardUserDefaults().setObject(refreshToken, forKey: "refresh_token")
NSUserDefaults.standardUserDefaults().setObject(openID, forKey: "openid")
NSUserDefaults.standardUserDefaults().synchronize() // 命令直接同步到文件里,来避免数据的丢失
}
self.wechatLoginByRequestForUserInfo()
}, failure: { (_, error) in
print(error)
})
}
}
}
// 获取用户个人信息(UnionID机制)
func wechatLoginByRequestForUserInfo() {
let accessToken = NSUserDefaults.standardUserDefaults().objectForKey("access_token")
let openID = NSUserDefaults.standardUserDefaults().objectForKey("openid")
// 获取用户信息
let params = ["access_token": accessToken! as! String, "openid": openID! as! String] as Dictionary
let AFN = AFHTTPSessionManager()
AFN.GET("https://api.weixin.qq.com/sns/userinfo", parameters: params, progress: nil, success: { (_, response) in
// 这里可以实现公司的要求,比如我司是微信登录成功后,通过segue跳转到主界面
print(response)
}, failure: { (_, error) in
print(error)
})
}