基於Swift語言開發微信、QQ和微博的SSO受權登陸代碼分析

前言

Swift 語言,怎麼說呢,有一種先接受後排斥。又歡迎的感受,縱觀國外大牛開源框架或項目演示,Swift差點兒佔領了多半,而國內儘管出現很是多相關技術介紹和教程,但是在真正項目開發中使用的佔領很是少部分。緣由一是眼下熟練它的開發人員並很少,二是版本號不太穩定,還需要更成熟可靠的版本號支持,但總之將來仍是很是有前景的。深有體會。不管是代碼量仍是編譯效率。以及語言特性。現代性都優於Object-C,預計興許會被蘋果做爲官方開發語言,值得期待。git


走起

鑑於此,筆者將以前用Object-C寫的SSO受權登陸:微信,QQ和微博。又一次用Swift語言寫一遍,以便需要的朋友參考。算是SSO受權登陸的姊妹篇;github


一,總體架構

1,引入第三方庫

除了必須引入相應的登陸SDK外,額外引入了SDWebImage。SVProgressHUD。看名字你們都明確吧。引入登陸SDK請各自看官方的開發文檔,需要增長什麼系統庫文件。需要配置Other Linker Flags 等,請參考各自官方文檔就能夠。json

2,配置鏈接橋文件

因爲建立的project是基於Swift語言,眼下官方SDK和其餘三方庫都是用OC寫的,因此爲了在swift中調用oc代碼。需要配置鏈接橋文件Bridging-Header.h,搜索objective-C bridging Header健,而後在值裏面輸入XXXLogin/Bridging-Header.h,注意是絕對路徑。裏面可以輸入需要調用的頭文件。如swift

#import "WXApi.h"
#import "SVProgressHUD.h"
#import "UIImageView+WebCache.h"


3,配置project

因爲是SSO跳轉方式,需要配置URL Schemes,以便程序返回識別宿主程序。配置方法很是easy,參考各自文檔就能夠。在info裏面可以可視化加入。各自的key值採用官方demo所提供。api

二,微信

1。註冊
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        
        //向微信註冊
        WXApi.registerApp(kWXAPP_ID)
        
        return true
    }

2,受權登陸
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        NSNotificationCenter.defaultCenter().addObserver(self, selector:"onRecviceWX_CODE_Notification:", name: "WX_CODE", object: nil)
        
        
        let sendBtn:UIButton = UIButton()
        sendBtn.frame = CGRectMake(30, 100, kIPHONE_WIDTH-60, 40)
        sendBtn.backgroundColor = UIColor.redColor()
        sendBtn.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
        sendBtn.setTitle("Swift版本號之微信受權登陸", forState: UIControlState.Normal)
        sendBtn.addTarget(self, action: "sendBtnClick:", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(sendBtn)
        
        
        headerImg = UIImageView(frame: CGRectMake(30, 160, 120, 120))
        headerImg.backgroundColor = UIColor.yellowColor()
        self.view.addSubview(headerImg)
        
        nicknameLbl.frame = CGRectMake(170, 160, kIPHONE_WIDTH-60-140, 40)
        nicknameLbl.backgroundColor = UIColor.lightGrayColor()
        nicknameLbl.textColor = UIColor.purpleColor()
        nicknameLbl.textAlignment = NSTextAlignment.Center
        self.view.addSubview(nicknameLbl)
        
    }
    
    
    func sendBtnClick(sneder:UIButton)
    {
        sendWXAuthRequest()
    }
    
    //微信登陸 第一步
    func sendWXAuthRequest(){
        
        let req : SendAuthReq = SendAuthReq()
        req.scope = "snsapi_userinfo,snsapi_base"
        WXApi .sendReq(req)
    }

3,回調
 func onResp(resp: BaseResp!) {
        
        /*
        
        ErrCode	ERR_OK = 0(用戶容許)
        ERR_AUTH_DENIED = -4(用戶拒絕受權)
        ERR_USER_CANCEL = -2(用戶取消)
        code	用戶換取access_token的code,僅在ErrCode爲0時有效
        state	第三方程序發送時用來標識其請求的惟一性的標誌,由第三方程序調用sendReq時傳入。由微信終端回傳。state字符串長度不能超過1K
        lang	微信client當前語言
        country	微信用戶當前國家信息
        */
        // var aresp resp :SendAuthResp!
        var aresp = resp as! SendAuthResp
        //  var aresp1 = resp as? SendAuthResp
        
        if (aresp.errCode == 0)
        {
            println(aresp.code)
            //031076fd11ebfa5d32adf46b37c75aax
            
            var dic:Dictionary<String,String>=["code":aresp.code];
            let value = dic["code"]
            println("code:\(value)")
            
            NSNotificationCenter.defaultCenter().postNotificationName("WX_CODE", object: nil, userInfo: dic)
            
        }
    }

4,獲取用戶信息

//微信回調通知,獲取code 第二步
    
    func onRecviceWX_CODE_Notification(notification:NSNotification)
    {
        SVProgressHUD.showSuccessWithStatus("獲取到code", duration: 1)
        
        var userinfoDic : Dictionary = notification.userInfo!
        let code: String = userinfoDic["code"] as! String
        
        println("Recevice Code: \(code)")
        
        self.getAccess_token(code)
    }
    
    //獲取token 第三步
    func getAccess_token(code :String){
        //https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
        
        var requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?

appid=\(kWXAPP_ID)&secret=\(kWXAPP_SECRET)&code=\(code)&grant_type=authorization_code" dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { var requestURL: NSURL = NSURL(string: requestUrl)! var data = NSData(contentsOfURL: requestURL, options: NSDataReadingOptions(), error: nil) dispatch_async(dispatch_get_main_queue(), { var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary println("Recevice Token: \(jsonResult)") SVProgressHUD.showSuccessWithStatus("獲取到Token和openid", duration: 1) let token: String = jsonResult["access_token"] as! String let openid: String = jsonResult["openid"] as! String self.getUserInfo(token, openid: openid) }) }) } //獲取用戶信息 第四步 func getUserInfo(token :String,openid:String){ // https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID var requestUrl = "https://api.weixin.qq.com/sns/userinfo?微信

access_token=\(token)&openid=\(openid)" dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { var requestURL: NSURL = NSURL(string: requestUrl)! var data = NSData(contentsOfURL: requestURL, options: NSDataReadingOptions(), error: nil) dispatch_async(dispatch_get_main_queue(), { var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary println("Recevice UserInfo: \(jsonResult)") /* Recevice UserInfo: { city = Chaoyang; country = CN; headimgurl = "http://wx.qlogo.cn/mmopen/FrdAUicrPIibcpGzxuD0kjfssQogj3icL8QTJQYUCLpgzSnvY6rJFGORreicPUiaPCzojwNlsXq4ibbc8e3gGFricWqJU5ia7ibicLVhfT/0"; language = "zh_CN"; nickname = "\U706b\U9505\U6599"; openid = "oyAaTjkR8T6kcKWyA4VPYDa_Wy_w"; privilege = ( ); province = Beijing; sex = 1; unionid = "o1A_Bjg52MglJiEjhLmB8SyYfZIY"; } */ SVProgressHUD.showSuccessWithStatus("獲取到用戶信息", duration: 1) let headimgurl: String = jsonResult["headimgurl"] as! String let nickname: String = jsonResult["nickname"] as! String self.headerImg.sd_setImageWithURL(NSURL(string: headimgurl)) self.nicknameLbl.text = nickname }) }) } 網絡



5,跳轉

 //微信的跳轉回調
    func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool    {
        return  WXApi.handleOpenURL(url, delegate: self)
    }
  func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool 
<span style="white-space:pre">	</span>{
        return  WXApi.handleOpenURL(url, delegate: self)
    }
    

三。QQ

1,註冊
    func sendBtnClick(sneder:UIButton)
    {
        sendQQAuthRequest()
    }
    
    //第一步  QQ登陸
    func sendQQAuthRequest(){
        
        tencentOAuth = TencentOAuth(appId: kQQAPP_ID, andDelegate: self)
        var permissions = [kOPEN_PERMISSION_GET_INFO,kOPEN_PERMISSION_GET_USER_INFO,kOPEN_PERMISSION_GET_SIMPLE_USER_INFO]
        tencentOAuth.authorize(permissions, inSafari: false)
        
    }


2,受權登陸

如上架構

3。回調

 //第二步 登陸成功回調
    func tencentDidLogin() {
        let accessToken = tencentOAuth.accessToken

        println("accessToken:\(accessToken)") //641B23508B62392C52D6DFADF67FAA9C

        getUserInfo()
    }
    
    //失敗
    func tencentDidNotLogin(cancelled: Bool) {
        println("登陸失敗了")
    }
    
    //無網絡
    func tencentDidNotNetWork() {
        println("沒有網絡")
    }
    

4。獲取用戶信息

 //第三步 獲取用戶信息
    func getUserInfo()
    {
        SVProgressHUD.showWithStatus("正在獲取用戶信息...")

        tencentOAuth.getUserInfo()
    }
    
    
    //第四步 在獲取用戶回調中獲取用戶信息
    func getUserInfoResponse(response: APIResponse!) {
        
        SVProgressHUD.dismissWithSuccess("獲取用戶信息成功", afterDelay: 1)

        var dic:Dictionary = response.jsonResponse
        
        println("dic:\(dic)")
        
        //        [is_lost: 0, figureurl: http://qzapp.qlogo.cn/qzapp/222222/C5527A2F775D9EA7C20317128FAC202B/30, vip: 0, is_yellow_year_vip: 0, province: 北京, ret: 0, is_yellow_vip: 0, figureurl_qq_1: http://q.qlogo.cn/qqapp/222222/C5527A2F775D9EA7C20317128FAC202B/40, yellow_vip_level: 0, level: 0, figureurl_1: http://qzapp.qlogo.cn/qzapp/222222/C5527A2F775D9EA7C20317128FAC202B/50, city: 海淀, figureurl_2: http://qzapp.qlogo.cn/qzapp/222222/C5527A2F775D9EA7C20317128FAC202B/100, nickname: 竹中雨滴, msg: , gender: 男, figureurl_qq_2: http://q.qlogo.cn/qqapp/222222/C5527A2F775D9EA7C20317128FAC202B/100]
        
        
        refeshUserInfo(dic)
    }
    
    
    //第五步 刷新用戶界面
    func refeshUserInfo(dic : NSDictionary){
    
        let headimgurl: String = dic["figureurl_qq_2"] as! String
        let nickname: String = dic["nickname"] as! String
        
        self.headerImg.sd_setImageWithURL(NSURL(string: headimgurl))
        self.nicknameLbl.text = nickname

    }
5。跳轉

  func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?

) -> Bool { return TencentOAuth.HandleOpenURL(url) } func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool { return TencentOAuth.HandleOpenURL(url) } app




四,微博

1。註冊

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        
        WeiboSDK.registerApp(kAppKey)
        
        return true
    }

2。受權登陸

func sendBtnClick(sneder:UIButton)
    {
        sendSinaAuthRequest()
    }
    
    //第一步  微博登陸
    func sendSinaAuthRequest(){
        
        var request : WBAuthorizeRequest = WBAuthorizeRequest.request() as! WBAuthorizeRequest
        request.redirectURI = kRedirectURI
        request.scope = "all"
        request.userInfo = ["SSO_Key":"SSO_Value"]
        WeiboSDK.sendRequest(request)
    }

3。回調

func didReceiveWeiboRequest(request: WBBaseRequest!) {

    }
    
    func didReceiveWeiboResponse(response: WBBaseResponse!) {
  
        if response.isKindOfClass(WBAuthorizeResponse){

            if (response.statusCode == WeiboSDKResponseStatusCode.Success) {
            
                var authorizeResponse : WBAuthorizeResponse = response as! WBAuthorizeResponse
                var userID = authorizeResponse.userID
                var accessToken = authorizeResponse.accessToken
                
                println("userID:\(userID)\naccessToken:\(accessToken)")
                
                var userInfo = response.userInfo as Dictionary
                
                NSNotificationCenter.defaultCenter().postNotificationName("SINA_CODE", object: nil, userInfo: userInfo)

            }
        }
    }

4。獲取用戶信息框架

//第二步  經過通知獲得登陸後獲取的用戶信息
    func onRecviceSINA_CODE_Notification(notification:NSNotification)
    {
        SVProgressHUD.showSuccessWithStatus("獲取到用戶信息", duration: 1)
        
        var userinfoDic : Dictionary = notification.userInfo!
        
        println("userInfo:\(userinfoDic)")
        
        
        /*
        userID:2627289515
        accessToken:2.002BqnrCyY87OC80500cab28Ofqd3B
        userInfo:
        [uid: 2627289515, remind_in: 647057, scope: invitation_write, refresh_token: 2.002BqnrCyY87OC10f7877765yPietB,
        app: {
        logo = "http://ww1.sinaimg.cn/square/65745bf7jw1ea399us692j2028028glf.jpg";
        name = "SDK\U5fae\U535a\U5e94\U7528demo";
        }, 
        access_token: 2.002BqnrCyY87OC80500cab28Ofqd3B, expires_in: 647057
        ]
        
        */
        
        var userAppInfo: Dictionary<String,String> = userinfoDic["app"] as! Dictionary
        
        refeshUserInfo(userAppInfo)
    }

    //第三步 刷新用戶界面
    func refeshUserInfo(dic : NSDictionary){
        
        let headimgurl: String = dic["logo"] as! String
        let nickname: String = dic["name"] as! String
        
        self.headerImg.sd_setImageWithURL(NSURL(string: headimgurl))
        self.nicknameLbl.text = nickname
    }


5,跳轉
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?

) -> Bool { return WeiboSDK.handleOpenURL(url, delegate: self) } func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool { return WeiboSDK.handleOpenURL(url, delegate: self) }


五,對照分析

1。demo狀況

微博demo代碼工整度完爆微信。QQ。看着很是舒服,心情也不錯。另外微博放在了github上面。適合pod管理。凝視也極好,微信文檔寫的挺不錯,QQ寫的簡直喪心病狂,需要極度耐心才幹看明確,表示很是無語,另外本三種方式受權登陸的源碼有償提供,如需可以郵件mmw05@163.com聯繫就能夠。

2,嵌入時間

微信算是很是easy嵌入SDK,QQ也還可以。微博需要注意boundID有限制。微信的邏輯算是比較冗餘繁瑣。從受權到獲取到用戶信息需要很是多接口,而QQ和微博可以直接從受權登錄回調中獲取到。是比較便捷的。從上面代碼可以看出來;

後記

從objective-C到Swift,蘋果力求簡約,但又不簡單,現代化的語言,一定在性能各方面優於傳統,僅僅是需要時間和不少其它的考驗,做爲開發人員。多一個選擇,豈不更好。


附圖:

相關文章
相關標籤/搜索