Android 一行代码即可将微信登陆集成到项目中

现在微信越来越火了,基本上每一个应用都会有一个微信登陆,于是跟同事商量着是不是写一个SDK出来,方便以后开发使用。写出来以后,本着开源的想法,还是分享给大家。本人的第二篇博客,如果哪里写的不好,请轻喷.....

废话不多说,直接进入整体。大家都知道,集成微信的功能,都要从微信开放平台上下载一个名为libammsdk.jar的文件,这个就不用多说了吧,大家上微信开放平台上下载就可以了。我自己封好的jar包链接如下:http://download.csdn.net/detail/q_probably/9714162

,大家只需要把这两个jar包放到自己的项目中,然后在项目的报名下新建一个wxapi的包名,然后在该报名下新建一个WXEntryActivity类,让这个类继承我的jar包中的WX_CallbackActivity类就可以了。要注意的是,这里的wxapi的包,必须建在主包名的下面。(一定要注意,不然不会走微信的回调)。然后在我们的配置文件中增加下面的代码:

<activity android:name=".wxapi.WXEntryActivity"
    android:exported="true"/>

重点来了,在做完上述准备工作之后,我们只需要一行代码,就可以集成了,我将自己测试的Demo中的代码贴出来:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    textView = (TextView) findViewById(R.id.textview);
    button = (Button) findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            WeChatLogin.getWXInfo(MainActivity.this, "wxdc1e388c3822c80b", "3baf1193c85774b3fd9d18447d76cab0", new LoginInfoCallback() {
                @Override
                public void onSuccess(LOGIN login, final String s) {
                   MainActivity.this.runOnUiThread(new Runnable() {
                       @Override
                       public void run() {
                           textView.setText(s);
                       }
                   });
                }

                @Override
                public void onError(LOGIN login, Throwable throwable) {
                    textView.setText("错误了");
                }
            });
        }
    });
}
其实很简单,我的MainActivity的布局文件中只有一个Button和一个Textview,当我点击Button的时候,就会调用WechatLogin这个类中的getWxInfo()方法,这个方法中有四个参数:第一个是 上下文,因为我在MainActivity中,所以我这里传的是MainActivity.this。第二个参数,是我们在微信开放平台注册的app_id了,这个不用多说吧。第三个参数跟第二个差不多,是和app_id对应的app_secret这个也不用多说。第四个参数呢,是我自己写的一个监听,当我们调起微信授权登陆页面点击确定登陆以后,最后会走到这个回调里面,然后我们就可以拿到微信得数据了。当然了,这里面肯定涉及到了网络请求,所以是在子线程中进行的,如果想要更新UI的话,还是需要在主线程中进行的,也就是runOnUiThread()方法了。除此之外,权限也是必不可少的嘛,

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
下面说一下大家可能遇到的问题,因为Android从6.0开始,权限就需要动态的去配置了,我在写的时候,为了省事,就将gradle文件做了以下的调整,

compileSdkVersion 22
minSdkVersion 16
targetSdkVersion 22
compile 'com.android.support:appcompat-v7:22.0.0'
 这里大家可以看得懂吧,我把sdkversion限定在了22,这样就不会出现权限的问题了。如果你的是23,你需要自己去动态的处理一下权限了。

后面有时间的话,我会增加动态权限的申请,暂时就先这样了。


下面的话,我把思路和代码跟大家顺一下,如果你感兴趣的话,可以看一下,其实也没什么,里面稍微复杂的应该就是回调了,相信懂回调的朋友看起来会很简单:


public class WX_CallbackActivity extends Activity implements IWXAPIEventHandler {
    private static LoginReqCallback _reqCallbrack;
    private static IWXAPI iwxapi;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        iwxapi.handleIntent(getIntent(),this);
    }


    @Override
    public void onReq(BaseReq baseReq) {

    }

    @Override
    public void onResp(BaseResp baseResp) {
        int errorCode = baseResp.errCode;
        switch (errorCode) {
            case BaseResp.ErrCode.ERR_OK:
                //用户同意
                String code = ((SendAuth.Resp) baseResp).code;
                if (_reqCallbrack != null) {
                    _reqCallbrack.complete(code);
                }
                finish();
                break;
            case BaseResp.ErrCode.ERR_AUTH_DENIED:
                //用户拒绝
                if (_reqCallbrack != null) {
                    _reqCallbrack.denied();
                }
                break;
            case BaseResp.ErrCode.ERR_USER_CANCEL:
                //用户取消
                if (_reqCallbrack != null) {
                    _reqCallbrack.cancel();
                }
                break;
            default:
                break;
        }
    }
    /**
     * 向微信发送登陆请求
     * @param reqCallbrack 请求的回调
     * @param app_id 在微信开放平台注册的app id
     * */
    public static void sendReq(Context context,String app_id, LoginReqCallback reqCallbrack) {
        iwxapi = WXAPIFactory.createWXAPI(context,app_id,true);
        iwxapi.registerApp(app_id);
        if( !iwxapi.isWXAppInstalled()){
            Toast.makeText(context, "请先安装微信应用", Toast.LENGTH_SHORT).show();
            return;
        }
        _reqCallbrack = reqCallbrack;
        SendAuth.Req req = new SendAuth.Req();
        req.scope = "snsapi_userinfo";
        req.state = "wechat_sdk_demo_test";
        iwxapi.sendReq(req);
    }
}

这里面就是让大家继承的那个activity的所有代码了,在这里我实现了IWXAPIEventHandler接口,在微信得官方文档上是WXEntryActivity实现的该接口,按照继承的思想,是一样的拉。在这里,除了必须要实现的onReq和onResp方法外,我写了一个sendReq()方法,参数分别是context上下文,app_id,和一个回调接口,该接口中有三个方法,如下所示

public interface LoginReqCallback {
    public void complete(String code);
    public void denied();
    public void cancel();
}
其中的三个方法分别对应,用户授权,拒绝和取消。在该类里面,首先我拿到了sendReq()方法传过来的回到接口,并将它赋给我类中的成员变量,这样当用户点击不同的操作的时候,会在onResp方法中,调用接口的不同方法,来将用户进行的操作传递给实现该接口的方法中,如果用户同意,我们就可以拿到code了。


import android.content.Context;
import android.util.Log;
import android.widget.Toast;

import com.llk.wechatlogin.activity.WX_CallbackActivity;
import com.llk.wechatlogin.data.WeChatTokenEntity;
import com.llk.wechatlogin.llk_enum.LOGIN;
import com.llk.wechatlogin.llk_interface.HttpCallbackListener;
import com.llk.wechatlogin.llk_interface.LoginInfoCallback;
import com.llk.wechatlogin.llk_interface.LoginReqCallback;
import com.llk.wechatlogin.utils.HttpUtil;

import org.json.JSONException;
import org.json.JSONObject;

/**
 * Created by QQY on 2016/12/16 0016.
 * 微信登陆,调用微信客户端登陆
 */
public class WeChatLogin {
    public WeChatLogin(){}

    /**
     * 获取微信授权,得到微信用户的信息
     *
     * */
    public static void getWXInfo(final Context context, final String app_id, final String app_secret, final LoginInfoCallback loginInfoCallback) {
        WX_CallbackActivity.sendReq(context,app_id, new LoginReqCallback() {
            @Override
            public void complete(String code) {
                Toast.makeText(context,"用户同意",Toast.LENGTH_SHORT).show();
                Log.e("---------->","用户同意");
                getToken(app_id,app_secret,code,loginInfoCallback);
            }

            @Override
            public void denied() {
                Toast.makeText(context,"用户拒绝",Toast.LENGTH_SHORT).show();
                loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("您已拒绝"));
            }

            @Override
            public void cancel() {
                Toast.makeText(context,"用户取消",Toast.LENGTH_SHORT).show();
                loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("成功取消"));
            }
        });
    }
    /**
     * 根据code获取token
     * @param code 微信登陆必须的code
     * @param loginInfoCallback 获取微信用户信息的回调
     * */
    private static void getToken(String app_id, String app_secret, String code, final LoginInfoCallback loginInfoCallback) {
        final String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" +
                app_id + "&secret=" + app_secret + "&code=" + code + "&grant_type=authorization_code";
        //发送网络请求
        HttpUtil.sendHttpRequest(url, new HttpCallbackListener() {
            @Override
            public void onFinish(String response) {
                try {
                    JSONObject jsonObject = new JSONObject(response);
                    if (jsonObject.optInt("errcode",-1) == -1) {
                        WeChatTokenEntity entity = new WeChatTokenEntity();
                        entity.access_token=jsonObject.optString("access_token","");
                        entity.openid=jsonObject.optString("openid","");
                        //调用获取微信信息的方法
                        getInfo(entity,loginInfoCallback);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onErrot(Exception e) {
                loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("请求异常"));
            }
        });
    }
    /**
     *获取微信用户信息
     * @param entity Token相关实体类
     * @param loginInfoCallback     回调接口
     * */
    private static void getInfo(WeChatTokenEntity entity, final LoginInfoCallback loginInfoCallback) {
        Log.e("------------>toiken",entity.access_token);
        String accessToken = entity.access_token;
        String openId = entity.openid;
        final String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId;
        HttpUtil.sendHttpRequest(url, new HttpCallbackListener() {
            @Override
            public void onFinish(String response) {
                try {
                    JSONObject json = new JSONObject(response);
                    if (json.optInt("errcode",-1) == -1) {
                        if (loginInfoCallback != null) {
                            Log.e("------------->",response);
                            loginInfoCallback.onSuccess(LOGIN.WEIXIN,response);
                        }else {
                            if (loginInfoCallback != null) {
                                loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("请求异常"));
                            }
                        }
                    }
                } catch (JSONException e) {
                    if (loginInfoCallback != null) {
                        loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("请求异常"));
                    }
                }
            }

            @Override
            public void onErrot(Exception e) {
                loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("请求异常"));
            }
        });
    }
}

在上面我们说过,只需要调用WechatLogin中degetWxInfo()方法就可以,这个方法中的参数,大家自己看代码就可以了,我就不多说了。在这个方法的一开始,我们调用了

WX_CallbackActivity.sendReq(context,app_id, new LoginReqCallback()
方法,这里new 出了一个LoginReqCallback()接口,这样就对应上上面所说的了,当用户授权以后,我们实现的complete()方法就可以拿到code了,拿到code以后,我们调用了getToken()方法来获取token。大家可以看到,我们在getWXInfo()方法传进来的LoginInfoCallback接口会一直传到最后面的getInfo()方法中,另外HttpCallBackListener回调接口是我们在向微信请求数据的监听回调,在我们发送网络请求的时候,也就是
 HttpUtil.sendHttpRequest(url, new HttpCallbackListener() 

这一行代码。该接口中两个方法,分别对应请求成功和请求失败,当我们请求成功以后,我们调用了从最上面的getWXInfo()方法中一直传过来的LoginInfoCallback接口中的onSuccess()方法,将我们请求到的数据传出去。这样我们在最开始调用getWXInfo()方法时候new 出来的 LofinInfoCallback接口实现的两个方法中,就可以拿到数据了。

基本的思路就是这样了,我把剩下的代码都给大家贴出来

/**
 * Created by QQY on 2016/12/17 0017.
 * 网络请求的回调
 */
public interface HttpCallbackListener {
    void onFinish(String response);
    void onErrot(Exception e);
}
public interface LoginInfoCallback {
    void onSuccess(LOGIN type, String response);
    void onError(LOGIN type, Throwable text);
}
public enum LOGIN {
    WEIXIN,
    SINA_WEIBO,
    QQ,
    PHONE_NUMBER
}
public class WeChatTokenEntity {
    public String access_token ;                  // 接口调用凭证
    public long expires_in;         //接口调用凭证超时时间,单位(秒)
    public String refresh_token ;                 // 用户刷新access_token
    public String  openid ;                        // 授权用户唯一标识
    public String scope ;                         // 用户授权的作用域,使用逗号(,)分隔
    public String unionid;         // 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
}

public class HttpUtil {
    /**
     * 发送一个网络请求的方法
     * @param address 要访问的地址
     * @param listener 回调接口
     * */
    public static void sendHttpRequest(final String address, final HttpCallbackListener listener) {
        //网络请求为耗时操作,在子线程中运行
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL url = new URL(address);
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    connection.setDoInput(true);
                    connection.setDoOutput(true);
                    InputStream in = connection.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    if (listener != null) {
                        //回调onFininsh()方法
                        listener.onFinish(response.toString());
                    }
                } catch (MalformedURLException e) {
                    listener.onErrot(e);
                } catch (IOException e) {
                    listener.onErrot(e);
                } finally {
                    if (connection != null) {
                        //断开连接
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
}

其中,大家看到了,有一个枚举,因为后面我们还要把微博、QQ登陆都封转一下,所以就可以通过枚举来区分到底是哪一种登陆,从而在LoginInfoCallback接口的两个回调方法中,就可以区分不同平台的数据了,就不用每一个登陆方式都写一个接口回调了。但是,每一个平台的登陆,还是要对应一个不同的方法的。


好了,就到这里了,如果大家有什么疑问的话,可以留言问我。我看到的话会尽量帮大家解决。重申一下,本人写的第二篇博客,写的不好的地方,希望大家理解,如果不喜欢实在想喷的话,请轻喷。




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值