cordova 实现第三方登录及分享

QQ、微信、微博,只针对移动应用或JS提供SDK,JS SDK表面上是最方便cordova项目实现的,但在授权是通过网页的,其session还需要在网页上输入用户名密码来建立,而android sdk和ios sdk的实现形式是调用本身已安装的第三方软件完成授权,显然后者才是我们想要的方式。

插件推荐:

(以下几个插件是我用到的,其他的我还试过一些,都不满意)

如果你看完整遍笔记觉得我改的也是你想要的,也可以用我改过的的QQ和微博插件:

笔记:

  1. 准备工作,分别到各个开放平台申请appid,添加测试账号

  2. 通过cordova添加插件

    注意:由于微信插件会改变根目录config.xml,所以我们需要伪造一个根目录的config.xml给它改(我的做法是从www里把config.xml复制一份出来根目录)

     //QQ:(注意把YOUR_QQ_APPID替换成第一步申请的QQ APPID)
     cordova plugin add https://github.com/iVanPan/Cordova_QQ.git --variable QQ_APP_ID=YOUR_QQ_APPID
      
     //微信:(注意把YOUR_WECHAT_APPID替换成第一步申请到的微信APPID)
     cordova plugin add https://github.com/xu-li/cordova-plugin-wechat --variable wechatappid=YOUR_WECHAT_APPID
      
     //微博:(注意把YOUR_WEIBO_APPID替换成第一步申请到的微博APPID)
     cordova plugin add https://github.com/iVanPan/cordova_weibo.git --variable WEIBO_APP_ID=YOUR_WEIBO_APPID
    
  3. 插件的进一步设置

    微博需要验证redirecturi,所以,如果在开放平台上有设置redirecturi,则需要在config.xml文件中加入以下属性:

     //YOUR_REDIRECT_URL替换为你在开放平台上设置的redirecturi
     <preference name="REDIRECTURI" value="YOUR_REDIRECT_URL" />
    

    微博插件中作者把so库的target地址写错了,修复方法如下

     //找到以下这一行
     <source-file src="src/android/libs/arm64-v8a/libweibosdkcore.so" target-dir="libs/arme64-v8a/" />
     
     //把最后的 arme64-v8a 改为 arm64-v8a ,如下
     <source-file src="src/android/libs/arm64-v8a/libweibosdkcore.so" target-dir="libs/arm64-v8a/" />
    
  4. 检查是否安装APP

     YCQQ.checkClientInstalled(function(){
         QQINSTALLED=true;
     },function(){
         // if installed QQ Client version is not supported sso,also will get this error
         QQINSTALLED=false;
     });
     Wechat.isInstalled(function (installed) {
         WEIXININSTALL=installed;
     });
     YCWeibo.checkClientInstalled(function(){
         WEIBOINSTALL=true;
     },function(){
         WEIBOINSTALL=false;
     });
    
  5. 第三方登录

     //QQ登录
     var checkClientIsInstalled = 1;//default is 0,only for iOS
     YCQQ.ssoLogin(function(args){
           alert(args.access_token);
           alert(args.userid);
           },function(failReason){
            console.log(failReason);
     },checkClientIsInstalled);
      
     //微信登录
     var scope = "snsapi_userinfo";
     Wechat.auth(scope, function (response) {
         // you may use response.code to get the access token.
         alert(JSON.stringify(response));
     }, function (reason) {
         alert("Failed: " + reason);
     });
      
     //微博登录
     YCWeibo.ssoLogin(function(args){
              alert(args.access_token);
              alert(args.userid);
           },function(failReason){
              console.log(failReason);
     });
    
  6. 第三方分享

     //QQ分享
     var args = {};
     args.url = "";
     args.title = "";
     args.description = "";
     args.imageUrl = "";
     args.appName = "";
     YCQQ.shareToQQ(function(){
         console.log("share success");
     },function(failReason){
         console.log(failReason);
     },args);
      
     //微信分享
     //Wechat.Scene.TIMELINE 表示分享到朋友圈
     //Wechat.Scene.SESSION 表示分享给好友
     //(1)文本
     Wechat.share({
         text: "This is just a plain string",
         scene: Wechat.Scene.TIMELINE   // share to Timeline
     }, function () {
         alert("Success");
     }, function (reason) {
         alert("Failed: " + reason);
     });
     //(2)媒体
     Wechat.share({
         message: {
             title: "Hi, there",
             description: "This is description.",
             thumb: "www/img/thumbnail.png",
             mediaTagName: "TEST-TAG-001",
             messageExt: "这是第三方带的测试字段",
             messageAction: "<action>dotalist</action>",
             media: "YOUR_MEDIA_OBJECT_HERE"
         },
         scene: Wechat.Scene.TIMELINE   // share to Timeline
     }, function () {
         alert("Success");
     }, function (reason) {
         alert("Failed: " + reason);
     });
     //(3)网页链接
     Wechat.share({
         message: {
             ...
             media: {
                 type: Wechat.Type.LINK,
                 webpageUrl: "http://tech.qq.com/zt2012/tmtdecode/252.htm"
             }
         },
         scene: Wechat.Scene.TIMELINE   // share to Timeline
     }, function () {
         alert("Success");
     }, function (reason) {
         alert("Failed: " + reason);
     });
      
     //微博分享(该插件只支持网页链接)
     var args = {};
     args.url = "http://www.baidu.com";
     args.title = "Baidu";
     args.description = "This is Baidu";
     args.imageUrl = "https://www.baidu.com/img/bdlogo.png";//if you don't have imageUrl,for android http://www.sinaimg.cn/blog/developer/wiki/LOGO_64x64.png will be the defualt one
     args.defaultText = "";
     YCWeibo.shareToWeibo(function () {
         alert("share success");
      }, function (failReason) {
         alert(failReason);
      }, args);
    
  7. 插件的改造

    1. SESSION的删除,YC采用了session缓存access_token的方式,导致我遇到一个问题,未调用登出而更换了其他第三方账号,则不能重新授权,由于项目的特殊性,所以我决定把session去掉。方法如下:

      • Android: YCQQ.java,查找 mTencent.isSessionValid() 并注释掉 if 和 else,只保留 else 中的代码
      • IOS: YCQQ.m,查找 self.tencentOAuth.isSessionValid 并注释掉 if 和 else,只保留 else 中的代码
    2. 微博分享URL并不实用,分享出去只能显示“网页链接”四个字,并没有图片及简介,估计要走申请审核,不过我没有找到入口,于是我决定把webpage方式的分享改为文本方式,以下是代码:

      (js中定义 args 时也要把内容写到 content 中)

      • Android: YCWeibo.java,查找 weiboMessage.mediaObject = getWebpageObj(params); 那一段,改为:

          TextObject textObject = new TextObject();
          textObject.identify = Utility.generateGUID();
          try{
              textObject.text = params.getString("content");
          } catch(JSONException e){
          }
          weiboMessage.mediaObject = textObject;
        
      • IOS: YCWeibo.m,注释 WBWebpageObject 那部分,添加代码:

          message.text=[params objectForKey:@"content"];
        
    3. QQ登录后返回openidaccess_token,但并不能通过ajax方式取得用户信息,所以我对登录方式做了修改,在登录成功后调用getUserInfo()方法取得用户信息,并加入openidaccess_token进去json集合才调用callback:

      • Android:YCQQ.java,import Context 和 UserInfo 两个包

          import android.content.Context;
          import com.tencent.connect.UserInfo;
        

        定义用于暂存 Context 和 JSONObject 的对象

          private Context context;
          private JSONObject qqRes;
        

        修改 pluginInitialize 方法:

          protected void pluginInitialize() {
          	super.pluginInitialize();
          	APP_ID = webView.getPreferences().getString(QQ_APP_ID, "");
          	context = this.cordova.getActivity().getApplicationContext();
          	mTencent = Tencent.createInstance(APP_ID, context);
          }
        

        找到以下行

          IUiListener loginListener = new IUiListener() {
        

          JSONObject jo = makeJson(mTencent.getAccessToken(),
          	mTencent.getOpenId());
          YCQQ.this.webView.sendPluginResult(new PluginResult(
          	PluginResult.Status.OK, jo), currentCallbackContext.getCallbackId());
        

        修改为

          qqRes=(JSONObject)response;
          UserInfo qqInfo = new UserInfo(context, mTencent.getQQToken());
          qqInfo.getUserInfo(new IUiListener() {
              @Override
              public void onError(UiError arg0) {
                  // TODO Auto-generated method stub
          		YCQQ.this.webView.sendPluginResult(new PluginResult(
                          PluginResult.Status.ERROR, QQ_LOGIN_ERROR), currentCallbackContext.getCallbackId());
              }
              @Override
              public void onComplete(Object json) {
                  // TODO Auto-generated method stub
                  try{
                      String access_token=qqRes.getString("access_token").toString();
                      String openid=qqRes.getString("openid").toString();
          			JSONObject qqJson=(JSONObject)json;
                      qqJson.put("access_token",access_token);
                      qqJson.put("openid",openid);
                      //mCallbackContext.success(qqJson);
                      YCQQ.this.webView.sendPluginResult(new PluginResult(
                              PluginResult.Status.OK, qqJson), currentCallbackContext.getCallbackId());
                  }
                  catch(JSONException e){
                  }
              }
              @Override
              public void onCancel() {
                  // TODO Auto-generated method stub
                  YCQQ.this.webView.sendPluginResult(new PluginResult(
                          PluginResult.Status.ERROR, QQ_CANCEL_BY_USER), currentCallbackContext.getCallbackId());
              }
          });
        
      • IOS:YCQQ.m,找到

          - (void)tencentDidLogin {
        

        在该方法结束后加入

          -(void)getUserInfoResponse:(APIResponse *)response {
              //登录成功需要在这里获取用户信息
              NSLog(@"respons:%@",response.jsonResponse);
              NSLog(@"nickName:%@",response.jsonResponse[@"nickname"]);
              NSMutableDictionary *Dic = [NSMutableDictionary dictionaryWithCapacity:2];
              [Dic setObject:response.jsonResponse[@"ret"] forKey:@"ret"];
              [Dic setObject:response.jsonResponse[@"msg"] forKey:@"msg"];
              [Dic setObject:response.jsonResponse[@"is_lost"] forKey:@"is_lost"];
              [Dic setObject:response.jsonResponse[@"nickname"] forKey:@"nickname"];
              [Dic setObject:response.jsonResponse[@"gender"] forKey:@"gender"];
              [Dic setObject:response.jsonResponse[@"province"] forKey:@"province"];
              [Dic setObject:response.jsonResponse[@"city"] forKey:@"city"];
              [Dic setObject:response.jsonResponse[@"figureurl"] forKey:@"figureurl"];
              [Dic setObject:response.jsonResponse[@"figureurl_1"] forKey:@"figureurl_1"];
              [Dic setObject:response.jsonResponse[@"figureurl_2"] forKey:@"figureurl_2"];
              [Dic setObject:response.jsonResponse[@"figureurl_qq_1"] forKey:@"figureurl_qq_1"];
              [Dic setObject:response.jsonResponse[@"figureurl_qq_2"] forKey:@"figureurl_qq_2"];
              [Dic setObject:response.jsonResponse[@"is_yellow_vip"] forKey:@"is_yellow_vip"];
              [Dic setObject:response.jsonResponse[@"vip"] forKey:@"vip"];
              [Dic setObject:response.jsonResponse[@"yellow_vip_level"] forKey:@"yellow_vip_level"];
              [Dic setObject:response.jsonResponse[@"level"] forKey:@"level"];
              [Dic setObject:response.jsonResponse[@"is_yellow_year_vip"] forKey:@"is_yellow_year_vip"];
              [Dic setObject:self.tencentOAuth.openId forKey:@"openid"];
              [Dic setObject:self.tencentOAuth.accessToken forKey:@"access_token"];
              CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:Dic];
              [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callback];
          }
        
  8. 重新生成平台,手动修改插件后,需要重新生成平台版本(如果你有在其他地方有改过生成后的文件,请记得重新设置)

     cordova platform rm android
     cordova platform rm ios
     cordova platform add android
     cordova platform add ios
    
  9. xcode需允许bitcode,因为新浪的库不符合

    build settings - > all -> 搜索 bitcode,把值改no

  10. xcode需做urltype的检查,有缺少则补充

    • tencentopenapi

      URL Schemes: tencent+appid

    • weibo

      URL Schemes: wb+appid

    • weixin

      URL Schemes: appid

若您觉得我的博文对您有帮助,欢迎点击下方按钮对我打赏
打赏