首页 > 代码库 > Android端不通过登录SDK实现QQ登录验证

Android端不通过登录SDK实现QQ登录验证

 通常的APP如果要调用QQ登录验证,需要使用QQ提供的登录SDK,但是QQ的SDK使用需要申请APP KEY和APPID,还要向腾讯提交比较繁琐的其它申请,而且如果通过该方法,登录信息全部被QQ掌握。那么是否有方法可以不申请DIY使用QQ登录验证呢。

     看了几个QQ移动产品,并未使用这种方式APP KEY的方式进行验证登录,大致确定QQ的产品并没有使用这种接口,而是使用自有的方法直接登录。于是找了一款产品分析了一下。

     首先确认了,登录的功能是由oicq这个包来负责的。



接下来分析它的调用接口,通过调试跟踪,确认了一登录过程都是在一个类中完成的。关键登录过程如下图:

第一步:通过QQ号和密码,发出登录请求



第二步:因为登录请求会有网络响应延时,接下来要做个登录响应监听,继承的监听类如下图:


第三步:监听响应后,就可以获取相关的登录返回信息了


 WloginSimpleInfo类存放返回信息中的几个比较基本的信息,像年龄、头像ID、性别、昵称等等,如下图:


基本上登录过程就是上面三步所示,实际代码略嫌啰嗦。

    那么要实现登录验证的功能,首先要使用oicq包,然后要把oicq的调用接口自已实现出来。

    一种方法是把oicq包的代码实现出来,用jd还原的代码尝试了一下,发现工作量超大,于是转换思路,寻找更为简便的方法。想到dex可以无损转换成jar包,那能不能直接把oicq文件 夹扣出来,做成jar包调用呢。

    实践了一下,发现确实可行,步骤如下:

    1.把classes.dex转换成XXXX.jar

    2.把XXXX.jar文件的扩展名改成zip,获取XXXX.zip文件

    3.用winrar打开XXXX.zip文件,把除了oicq以外的文件夹全部删掉,保存压缩文件为副本oicq.jar

这样获得的jar文件,可以做为第三方包导入到工程里

 

     剩下的就是实现oicq的调用接口了,把前面三步的逆向代码整理,简化了一下,添加两个类


[java] view plaincopy

  1. public class QQLogin {  

  2.   

  3.       private Context mContext;  

  4.       private QQLoginListener nListener;  

  5.       WtloginHelper wh;  

  6.       int userAge = 0;  

  7.       int gender = 0;  

  8.       String nickName = "";  

  9.       Handler notifyHandler;  

  10.         

  11.       public QQLogin(Context paramContext,Handler msgHandler)  

  12.       {  

  13.         mContext = paramContext;  

  14.         nListener = new QQLoginListener(this);  

  15.         notifyHandler = msgHandler;  

  16.       }  

  17.         

  18.       public int getUserAge()  

  19.       {  

  20.           return userAge;  

  21.       }  

  22.       public String getUserNickname()  

  23.       {  

  24.           return nickName;  

  25.       }  

  26.       public void getUserInfo(String userAccount, WUserSigInfo userSigInfo)  

  27.       {  

  28.           Log.v("getUserInfo","in:"+userAccount);  

  29.           if(userAccount != null ) {                  

  30.                 WloginSimpleInfo simpleInfo = new WloginSimpleInfo();                 

  31.                 Boolean v2 = wh.GetBasicUserInfo(userAccount, simpleInfo);  

  32.                 userAge = (simpleInfo._age[0]& 0xFF);  

  33.                 gender =  (simpleInfo._gander[0]& 0xFF);  

  34.                 Log.v("gander",gender+"");  

  35.                 nickName = new String(simpleInfo._nick);  

  36.                 Log.v("age",userAge + "");                               

  37.                 Log.v("nick",nickName);               

  38.           }  

  39.           else  

  40.           {  

  41.               Log.v("getUserInfo","account null");  

  42.           }  

  43.           notifyHandler.sendEmptyMessage(1);  

  44.       }  

  45.         

  46.       public void LoginError()  

  47.       {  

  48.           notifyHandler.sendEmptyMessage(2);  

  49.       }  

  50.         

  51.     //Set Login QQ Num and Password  

  52.     //Set Login CallBack  

  53.     public void SetLogin(String username,String passwd)  

  54.     {  

  55.         Log.e("SetLogin","start");  

  56.         wh = new WtloginHelper(mContext);  

  57.         wh.SetTimeOut(0);  

  58.         wh.SetListener(nListener);  

  59.         wh.SetAppClientVersion(4010010);  

  60.               

  61.               

  62.         WUserSigInfo usi = new WUserSigInfo();  

  63.         wh.GetStWithPasswd(username, 83886593, passwd, usi);  

  64.     }  

  65.       

  66.     static void onGetStWithPasswd(QQLogin nl, String userAccount, WUserSigInfo userSigInfo, int ret, ErrMsg errMsg) {  

  67.         Log.e("onGetStWithPasswd",userAccount);  

  68.           

  69.         nl.onGetStWithPasswd(userAccount, userSigInfo, ret, errMsg);  

  70.     }  

  71.   

  72.     private  void onGetStWithPasswd(String userAccount, WUserSigInfo userSigInfo, int ret, ErrMsg errMsg) {  

  73.         switch(ret) {  

  74.         //login success  

  75.             case 0: {    

  76.                 Log.e("getUserInfo",userAccount);  

  77.                 getUserInfo(userAccount, userSigInfo);  

  78.                 break;  

  79.             }  

  80.             //login error  

  81.             default:{  

  82.                 LoginError();  

  83.                 break;  

  84.             }  

  85.                   

  86.         }  

  87.     }  

  88. }  

下面是监听类:


[java] view plaincopy

  1. import oicq.wlogin_sdk.request.WUserSigInfo;  

  2. import oicq.wlogin_sdk.request.WtloginListener;  

  3. import oicq.wlogin_sdk.tools.ErrMsg;  

  4.   

  5.   

  6. class QQLoginListener extends WtloginListener {  

  7.     private QQLogin nl;   

  8.     public QQLoginListener(QQLogin arg1) {  

  9.         nl = arg1;          

  10.     }  

  11.   

  12.     public void OnCheckPictureAndGetSt(String arg2, byte[] arg3, WUserSigInfo arg4, int arg5, ErrMsg   

  13.             arg6) {  

  14.     }  

  15.   

  16.     public void OnException(ErrMsg arg5, int arg6, WUserSigInfo arg7) {  

  17.   

  18.     }  

  19.     //login with password callback  

  20.     public void OnGetStWithPasswd(String userAccount, long dwAppid, int dwMainSigMap, long dwSubDstAppid, String userPasswd, WUserSigInfo   

  21.             userSigInfo, int ret, ErrMsg errMsg) {  

  22.         QQLogin.onGetStWithPasswd(nl, userAccount, userSigInfo, ret, errMsg);  

  23.     }  

  24.   

  25.     public void OnGetStWithoutPasswd(String arg2, long arg3, long arg5, int arg7, long arg8, WUserSigInfo   

  26.             arg10, int arg11, ErrMsg arg12) {  

  27.     }  

  28.   

  29.     public void OnRefreshPictureData(String arg4, WUserSigInfo arg5, byte[] arg6, int arg7, ErrMsg arg8) {  

  30.         if(arg7 == 0) {  

  31.         }  

  32.     }  

  33. }  



下面是修改过的MainActivity代码:

[java] view plaincopy

  1. public class MainActivity extends Activity {  

  2.   

  3.     public EditText qqnum = null;  

  4.     public EditText passwd = null;  

  5.     public TextView userage = null;  

  6.     public TextView usernick = null;  

  7.     private ProgressBar xh_ProgressBar;    

  8.     Context mContext = this;  

  9.     QQLogin qqLogin = null;  

  10.           

  11.   

  12.     Handler myHandler = new Handler() {    

  13.           

  14.         @Override    

  15.         public void handleMessage(Message msg) {    

  16.     

  17.             switch (msg.what) {    

  18.             //login success  

  19.             case 1:    

  20.                 {      

  21.                     String age = "年龄:" + qqLogin.getUserAge();  

  22.                     String nick = "昵称:"+qqLogin.getUserNickname();  

  23.                     userage.setText(age);  

  24.                     usernick.setText(nick);  

  25.                     xh_ProgressBar.setVisibility(View.INVISIBLE);   

  26.                     break;    

  27.                 }  

  28.                 //login error  

  29.             case 2:    

  30.                 {      

  31.                     String age = "登录错误";  

  32.                     userage.setText(age);  

  33.                     usernick.setText("");  

  34.                     xh_ProgressBar.setVisibility(View.INVISIBLE);   

  35.                     break;    

  36.                 }  

  37.             }    

  38.             super.handleMessage(msg);    

  39.         }    

  40.     };  

  41.           

  42.     @Override  

  43.     protected void onCreate(Bundle savedInstanceState) {  

  44.         super.onCreate(savedInstanceState);  

  45.         setContentView(R.layout.activity_main);  

  46.           

  47.         qqnum = (EditText)findViewById(R.id.qqnum);  

  48.         passwd = (EditText)findViewById(R.id.passwd);  

  49.         userage = (TextView)findViewById(R.id.age);    

  50.         usernick = (TextView)findViewById(R.id.nick);    

  51.           

  52.         Button btnTest = (Button) findViewById(R.id.login);    

  53.         xh_ProgressBar = (ProgressBar) findViewById(R.id.ProgressBar01);   

  54.   

  55.         btnTest.setOnClickListener(new Button.OnClickListener() {  // 注1    

  56.    

  57.             @Override  

  58.             public void onClick(View v) {  

  59.                 // TODO Auto-generated method stub  

  60.                 String myqqnum = qqnum.getText().toString();  

  61.                 String mypassword = passwd.getText().toString();  

  62.                 Log.v(myqqnum,mypassword);  

  63.                   

  64.                 qqLogin = new QQLogin(mContext,myHandler);  

  65.                 qqLogin.SetLogin(myqqnum,mypassword);  

  66.                 xh_ProgressBar.setVisibility(View.VISIBLE);   

  67.             }    

  68.     

  69.         });   

  70.     }  

  71. }  

总结:对于混淆过且难以还原出源码的包,可以直接整个嫁接过来使用,其它APK也同样适用。

demo工程源代码下载


本文出自 “勿勿过客” 博客,请务必保留此出处http://justfwd.blog.51cto.com/9536001/1568979

Android端不通过登录SDK实现QQ登录验证