微信登陆的坑

转载注明:http://blog.csdn.net/ning_gg/article/details/52367130
去年做过微信支付,当时用的登陆是第三方的shareSDK。记得当初做微信支付的时候发现很坑,但是距今时隔久远记不清坑在哪里了。当shareSDK的密码忘了又只需要微信一个登陆接口的话,所以就想自己来实现微信登陆了。发现又重蹈覆辙,又入坑了,当入坑了才想起MD以前也入了这坑。所以这次记录下来,防止下回又坑。

这坑是微信会缓存我的登陆信息,所以第一次没有调成功的话需要清除微信缓存,不是聊天缓存而是数据库缓存。从手机设置的应用管理里面去清除应用数据(当然这会清除所有的聊天记录,所以建议用模拟器来调试程序)

附上微信登陆的代码,以后要用的话直接拷贝即可使用
在包名下面新建一个wxapi的包
然后事先准备的appket 与app_secret就不说了
app的签名签名是MD5不是SHA码(切记切记)

WXEntryActivity.class
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.imapedia.MainActivity;
import com.imapedia.R;
import com.tencent.mm.sdk.modelbase.BaseReq;
import com.tencent.mm.sdk.modelbase.BaseResp;
import com.tencent.mm.sdk.modelmsg.SendAuth;
import com.tencent.mm.sdk.modelmsg.SendAuth.Resp;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.sdk.openapi.WXAPIFactory;

import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

/**
 * Created by pailiao on 2016/8/29.
 */
public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
    private String TAG=WXEntryActivity.class.getSimpleName();
    protected static final int RETURN_OPENID_ACCESSTOKEN = 0;// 返回openid,accessToken消息码
    protected static final int RETURN_NICKNAME_UID = 1; // 返回昵称,uid消息码

    public static final String APP_ID = "lalalalalalal";// 微信开放平台申请到的app_id
    public static final String APP_SECRET = "lalalalalalalla";// 微信开放平台申请到的app_id对应的app_secret
    private static final String WEIXIN_SCOPE = "snsapi_userinfo";// 用于请求用户信息的作用域
    private static final String WEIXIN_STATE = "login_state"; // 自定义

    private IWXAPI api;
    private SendAuth.Req req;

    private Button login;

    private Handler handler =new Handler( new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case RETURN_OPENID_ACCESSTOKEN:
                    Bundle bundle1 = (Bundle) msg.obj;
                    String accessToken = bundle1.getString("access_token");
                    String openId = bundle1.getString("open_id");

                    getUID(openId, accessToken);
                    break;

                case RETURN_NICKNAME_UID:
                    Bundle bundle2 = (Bundle) msg.obj;
                    String nickname = bundle2.getString("nickname");
                    String uid = bundle2.getString("unionid");
                    Log.e( TAG,"昵称=="+nickname+",uid=="+uid );

                    Toast.makeText( WXEntryActivity.this,"欢迎进来=="+nickname,Toast.LENGTH_SHORT ).show();
                    startActivity( new Intent( WXEntryActivity.this, MainActivity.class ) );
                    finish();
                    break;

                default:
                    break;
            }
            return false;
        }
    } );
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );

        setContentView( R.layout.activity_wxentry);
        api = WXAPIFactory.createWXAPI(this, APP_ID, false);
        api.registerApp(APP_ID);//
        api.handleIntent(getIntent(), this);

        login=(Button) findViewById( R.id.login );
        login.setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                req = new SendAuth.Req();
                req.scope = WEIXIN_SCOPE;
                req.state = WEIXIN_STATE;
                api.sendReq(req);
                finish();
            }
        } );


    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent( intent );
        Log.e( TAG,"onNewIntent" );
        setIntent( intent );
        api.handleIntent(intent, this);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult( requestCode, resultCode, data );
        Log.e( TAG,"在这里回调的" );
    }

    @Override
    public void onReq(BaseReq baseReq) {

    }
    /**
     * Title: onResp
     *
     *           API:https://open.weixin.qq.com/ cgi- bin/showdocument ?action=dir_list&t=resource/res_list&verify=1&id=open1419317853 &lang=zh_CN
     * Description:在此处得到Code之后调用https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
     *  获取到token和openID。之后再调用https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID 获取用户个人信息
     *
     * @param arg0
     * @see com.tencent.mm.sdk.openapi.IWXAPIEventHandler#onResp(com.tencent.mm.sdk.openapi.BaseResp)
     */
    @Override
    public void onResp(BaseResp baseResp) {
        int result = 0;
        SendAuth.Resp sendAuthResp = (Resp) baseResp;// 用于分享时不要有这个,不能强转
        String code = sendAuthResp.code;
        switch (baseResp.errCode) {
            case BaseResp.ErrCode.ERR_OK:
                result = R.string.errcode_success;
                getResult(code);
                break;
            case BaseResp.ErrCode.ERR_USER_CANCEL:
                result = R.string.errcode_cancel;
                break;
            case BaseResp.ErrCode.ERR_AUTH_DENIED:
                result = R.string.errcode_deny;
                break;
            default:
                result = R.string.errcode_unknown;
                break;
        }

        Toast.makeText(this, result, Toast.LENGTH_LONG).show();


    }

    /**
     * 获取openid accessToken值用于后期操作
     * @param code 请求码
     */
    private void getResult(final String code) {
        new Thread() {// 开启工作线程进行网络请求
            public void run() {
                String path = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
                        + APP_ID
                        + "&secret="
                        + APP_SECRET
                        + "&code="
                        + code
                        + "&grant_type=authorization_code";
                try {
                    JSONObject jsonObject = JsonUtils
                            .initSSLWithHttpClinet(path);// 请求https连接并得到json结果
                    if (null != jsonObject) {
                        String openid = jsonObject.getString("openid")
                                .toString().trim();
                        String access_token = jsonObject
                                .getString("access_token").toString().trim();
                        Log.i(TAG, "openid = " + openid);
                        Log.i(TAG, "access_token = " + access_token);

                        Message msg = handler.obtainMessage();
                        msg.what = RETURN_OPENID_ACCESSTOKEN;
                        Bundle bundle = new Bundle();
                        bundle.putString("openid", openid);
                        bundle.putString("access_token", access_token);
                        msg.obj = bundle;
                        handler.sendMessage(msg);
                    }
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                return;
            };
        }.start();
    }

    /**
     * 获取用户唯一标识
     * @param openId
     * @param accessToken
     */
    private void getUID(final String openId, final String accessToken) {
        new Thread() {
            @Override
            public void run() {
                String path = "https://api.weixin.qq.com/sns/userinfo?access_token="
                        + accessToken + "&openid=" + openId;
                JSONObject jsonObject = null;
                try {
                    jsonObject = JsonUtils.initSSLWithHttpClinet(path);
                    String nickname = jsonObject.getString("nickname");
                    String unionid = jsonObject.getString("unionid");
                    Log.i(TAG, "nickname = " + nickname);
                    Log.i(TAG, "unionid = " + unionid);

                    Message msg = handler.obtainMessage();
                    msg.what = RETURN_NICKNAME_UID;
                    Bundle bundle = new Bundle();
                    bundle.putString("nickname", nickname);
                    bundle.putString("unionid", unionid);
                    msg.obj = bundle;
                    handler.sendMessage(msg);
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            };
        }.start();
    }
}
HTTPSTrustManager.class
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
 * @description 有一个信任管理器类负责决定是否信任远端的证书  X509TrustManager
 * @charset UTF-8
 * Created by pailiao on 2016/8/29.
 * @version
 */
public class HTTPSTrustManager implements X509TrustManager {

    private static TrustManager[] trustManagers;
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};

    /**
     * 该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,
     * 因此我们只需要执行默认的信任管理器的这个方法。JSSE中,默认的信任管理器类为TrustManager。
     */
    @Override
    public void checkClientTrusted(
            java.security.cert.X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException {
        // To change body of implemented methods use File | Settings | File
        // Templates.
    }

    /**
     * 该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。在实现该方法时,
     * 也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。
     */
    @Override
    public void checkServerTrusted(
            java.security.cert.X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException {
        // To change body of implemented methods use File | Settings | File
        // Templates.
    }

    public boolean isClientTrusted(X509Certificate[] chain) {
        return true;
    }

    public boolean isServerTrusted(X509Certificate[] chain) {
        return true;
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return _AcceptedIssuers;
    }

    public static void allowAllSSL() {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }

        });

        SSLContext context = null;
        if (trustManagers == null) {
            trustManagers = new TrustManager[] { new HTTPSTrustManager() };
        }

        try {
            context = SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        HttpsURLConnection.setDefaultSSLSocketFactory(context
                .getSocketFactory());
    }

}
JsonUtils.class
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;
import org.json.JSONObject;


import android.util.Log;

/**
 * @description jison工具类
 * @charset UTF-8
 *Created by pailiao on 2016/8/29.
 * @version
 */
public class JsonUtils {
    public static JSONObject initSSLWithHttpClinet(String path)
            throws ClientProtocolException, IOException {
        HTTPSTrustManager.allowAllSSL();
        JSONObject jsonObject = null;
        int timeOut = 30 * 1000;
        HttpParams param = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(param, timeOut);
        HttpConnectionParams.setSoTimeout(param, timeOut);
        HttpConnectionParams.setTcpNoDelay(param, true);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory .getSocketFactory(), 80));
        registry.register(new Scheme("https", TrustAllSSLSocketFactory .getDefault(), 443));
        ClientConnectionManager manager = new ThreadSafeClientConnManager( param, registry);
        DefaultHttpClient client = new DefaultHttpClient(manager, param);

        HttpGet request = new HttpGet(path);
        // HttpGet request = new HttpGet("https://www.alipay.com/");
        HttpResponse response = client.execute(request);
        HttpEntity entity = response.getEntity();
        BufferedReader reader = new BufferedReader(new InputStreamReader( entity.getContent()));
        StringBuilder result = new StringBuilder();
        String line = "";
        while ((line = reader.readLine()) != null) {
            result.append(line);
            try {
                jsonObject = new JSONObject(line);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        Log.e("HTTPS TEST", result.toString());
        return jsonObject;
    }
}
TrustAllSSLSocketFactory.class
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;

import android.os.Build;

/**
 *
 * @description ssl安全链接工厂 
 * @charset UTF-8
 * Created by pailiao on 2016/8/29.
 * @version
 */
public class TrustAllSSLSocketFactory  extends SSLSocketFactory   {

    private javax.net.ssl.SSLSocketFactory factory;
    private static TrustAllSSLSocketFactory instance;

    private TrustAllSSLSocketFactory() throws KeyManagementException, UnrecoverableKeyException,
            NoSuchAlgorithmException, KeyStoreException {
        super(null);

        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, new TrustManager[] { new TrustAllManager() }, null);
        factory = context.getSocketFactory();
        setHostnameVerifier(new X509HostnameVerifier() {

            @Override
            public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {

            }

            @Override
            public void verify(String host, X509Certificate cert) throws SSLException {

            }

            @Override
            public void verify(String host, SSLSocket ssl) throws IOException {

            }

            @Override
            public boolean verify(String host, SSLSession session) {
                return true;
            }
        });
    }

    public static SocketFactory getDefault() {
        if (instance == null) {
            try {
                instance = new TrustAllSSLSocketFactory();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return instance;
    }

    @Override
    public Socket createSocket() throws IOException {
        return factory.createSocket();
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
            throws IOException, UnknownHostException {
        if (Build.VERSION.SDK_INT < 11) { // 3.0
            injectHostname(socket, host);
        }

        return factory.createSocket(socket, host, port, autoClose);
    }

    private void injectHostname(Socket socket, String host) {
        try {
            Field field = InetAddress.class.getDeclaredField("hostName");
            field.setAccessible(true);
            field.set(socket.getInetAddress(), host);
        } catch (Exception ignored) {
        }
    }

    public class TrustAllManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {

        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }

}

代码就这些了,最后带上manifast文件中WXEntryActivity的声明

<activity android:name=".wxapi.WXEntryActivity"
                  android:exported="true"
                  android:launchMode="singleTop"
                  android:label="@string/app_name"
            />

add:

private IWXAPI api;
         api = WXAPIFactory.createWXAPI(this, APP_ID, false);
         //可以判断用户是否已经安装微信
         api.isWXAppInstalled()

除了每次调试要清除微信应用缓存其实没什么难的。
转载注明:http://blog.csdn.net/ning_gg/article/details/52367130

你可能感兴趣的:(android中级基础)