// GeneralAppliction.java public static IWXAPI sApi; @Override public void onCreate() { super.onCreate(); sApi = WXEntryActivity.initWeiXin(this, AppConst.WEIXIN_APP_ID); }
// MainActivity.java WXEntryActivity.loginWeixin(MainActivity.this, GeneralAppliction.sApi);
下面對具體的集成步驟作詳細的描述。html
集成步驟:java
這一步其實不用怎麼講,沒法就是在微信開放平臺上註冊一個帳號,而後建立移動應用。android
須要注意的是:應用簽名的部分api
下載後把libammsdk.jar文件拷貝到AS工程的libs目錄,並把示例Demo裏源文件目錄下的wxapi目錄整個拷貝到,工程目錄的src下的根包下:安全
若是wxapi這個文件夾放的位置不對,講沒法登陸,微信sdk沒法找到登陸的Activity受權功能。而後在Manifest.xml裏面加入:微信
<activity android:name=".wxapi.WXEntryActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar" android:configChanges="keyboardHidden|orientation|screenSize" android:exported="true" android:screenOrientation="portrait" />
全局初始化微信組件,固然是Application的onCreate裏(固然Activity的onCreate也是能夠的,爲了全局使用微信api對象方便操做):網絡
@Override public void onCreate() { super.onCreate(); // 初始化微信組件 initWeiXin(); } public static IWXAPI sApi; private void initWeiXin() { sApi = WXEntryActivity.initWeiXin(this, AppConst.WEIXIN_APP_ID); }
爲了同一業務的單一原則我把微信相關的都統一封裝到了wxapi包下和WXEntryActivity中:session
// 實現IWXAPIEventHandler 接口,以便於微信事件處理的回調 public class WXEntryActivity extends Activity implements IWXAPIEventHandler { private static final String WEIXIN_ACCESS_TOKEN_KEY = "wx_access_token_key"; private static final String WEIXIN_OPENID_KEY = "wx_openid_key"; private static final String WEIXIN_REFRESH_TOKEN_KEY = "wx_refresh_token_key"; private Gson mGson; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 微信事件回調接口註冊 GeneralAppliction.sApi.handleIntent(getIntent(), this); mGson = new Gson(); } /** * 微信組件註冊初始化 * @param context 上下文 * @param weixin_app_id appid * @return 微信組件api對象 * / public static IWXAPI initWeiXin(Context context, @NonNull String weixin_app_id) { if (TextUtils.isEmpty(weixin_app_id)) { Toast.makeText(context.getApplicationContext(), "app_id 不能爲空", Toast.LENGTH_SHORT).show(); } IWXAPI api = WXAPIFactory.createWXAPI(context, weixin_app_id, true); api.registerApp(weixin_app_id); return api; } /** * 登陸微信 * * @param api 微信服務api */ public static void loginWeixin(Context context, IWXAPI api) { // 判斷是否安裝了微信客戶端 if (!api.isWXAppInstalled()) { Toast.makeText(context.getApplicationContext(), "您還未安裝微信客戶端!", Toast.LENGTH_SHORT).show(); return; } // 發送受權登陸信息,來獲取code SendAuth.Req req = new SendAuth.Req(); // 應用的做用域,獲取我的信息 req.scope = "snsapi_userinfo"; /** * 用於保持請求和回調的狀態,受權請求後原樣帶回給第三方 * 爲了防止csrf攻擊(跨站請求僞造攻擊),後期改成隨機數加session來校驗 */ req.state = "app_wechat"; api.sendReq(req); } // 微信發送請求到第三方應用時,會回調到該方法 @Override public void onReq(BaseReq req) { switch (req.getType()) { case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX: break; case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX: break; default: break; } } // 第三方應用發送到微信的請求處理後的響應結果,會回調到該方法 @Override public void onResp(BaseResp resp) { switch (resp.errCode) { // 發送成功 case BaseResp.ErrCode.ERR_OK: // 獲取code String code = ((SendAuth.Resp) resp).code; // 經過code獲取受權口令access_token getAccessToken(code); break; } } }
小夥伴有疑問code是啥玩意:
第三方經過code進行獲取access_token的時候須要用到,code的超時時間爲10分鐘,一個code只能成功換取一次access_token即失效。code的臨時性和一次保障了微信受權登陸的安全性。第三方可經過使用https和state參數,進一步增強自身受權登陸的安全性。app
這樣客戶端使用的地方只要:ide
WXEntryActivity.loginWeixin(MainActivity.this, GeneralAppliction.sApi);
咱們在onResp的回調方法中獲取了code,而後經過code獲取受權口令access_token:
/** * 獲取受權口令 */ private void getAccessToken(String code) { String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + "appid=" + AppConst.WEIXIN_APP_ID + "&secret=" + AppConst.WEIXIN_APP_SECRET + "&code=" + code + "&grant_type=authorization_code"; // 網絡請求獲取access_token httpRequest(url, new ApiCallback<String>() { @Override public void onSuccess(String response) { Logger.e(response); // 判斷是否獲取成功,成功則去獲取用戶信息,不然提示失敗 processGetAccessTokenResult(response); } @Override public void onError(int errorCode, final String errorMsg) { Logger.e(errorMsg); showMessage("錯誤信息: " + errorMsg); } @Override public void onFailure(IOException e) { Logger.e(e.getMessage()); showMessage("登陸失敗"); } }); } /** * 處理獲取的受權信息結果 * @param response 受權信息結果 */ private void processGetAccessTokenResult(String response) { // 驗證獲取受權口令返回的信息是否成功 if (validateSuccess(response)) { // 使用Gson解析返回的受權口令信息 WXAccessTokenInfo tokenInfo = mGson.fromJson(response, WXAccessTokenInfo.class); Logger.e(tokenInfo.toString()); // 保存信息到手機本地 saveAccessInfotoLocation(tokenInfo); // 獲取用戶信息 getUserInfo(tokenInfo.getAccess_token(), tokenInfo.getOpenid()); } else { // 受權口令獲取失敗,解析返回錯誤信息 WXErrorInfo wxErrorInfo = mGson.fromJson(response, WXErrorInfo.class); Logger.e(wxErrorInfo.toString()); // 提示錯誤信息 showMessage("錯誤信息: " + wxErrorInfo.getErrmsg()); } } /** * 驗證是否成功 * * @param response 返回消息 * @return 是否成功 */ private boolean validateSuccess(String response) { String errFlag = "errmsg"; return (errFlag.contains(response) && !"ok".equals(response)) || (!"errcode".contains(response) && !errFlag.contains(response)); }
在回調的onResp方法中獲取code後,處理access_token是否登陸過或者過時的問題:
// 從手機本地獲取存儲的受權口令信息,判斷是否存在access_token,不存在請求獲取,存在就判斷是否過時 String accessToken = (String) ShareUtils.getValue(this, WEIXIN_ACCESS_TOKEN_KEY, "none"); String openid = (String) ShareUtils.getValue(this, WEIXIN_OPENID_KEY, ""); if (!"none".equals(accessToken)) { // 有access_token,判斷是否過時有效 isExpireAccessToken(accessToken, openid); } else { // 沒有access_token getAccessToken(code); }
判斷受權口令是否有效:
/** * 判斷accesstoken是過時 * @param accessToken token * @param openid 受權用戶惟一標識 */ private void isExpireAccessToken(final String accessToken, final String openid) { String url = "https://api.weixin.qq.com/sns/auth?" + "access_token=" + accessToken + "&openid=" + openid; httpRequest(url, new ApiCallback<String>() { @Override public void onSuccess(String response) { Logger.e(response); if (validateSuccess(response)) { // accessToken沒有過時,獲取用戶信息 getUserInfo(accessToken, openid); } else { // 過時了,使用refresh_token來刷新accesstoken refreshAccessToken(); } } @Override public void onError(int errorCode, final String errorMsg) { Logger.e(errorMsg); showMessage("錯誤信息: " + errorMsg); } @Override public void onFailure(IOException e) { Logger.e(e.getMessage()); showMessage("登陸失敗"); } }); }
/**
* 刷新獲取新的access_token
*
/
private void refreshAccessToken() {
// 從本地獲取以存儲的refresh_token
final String refreshToken = (String) ShareUtils.getValue(this, WEIXIN_REFRESH_TOKEN_KEY, "");
if (TextUtils.isEmpty(refreshToken)) {
return;
}
// 拼裝刷新access_token的url請求地址
String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?" +
"appid=" + AppConst.WEIXIN_APP_ID +
"&grant_type=refresh_token" +
"&refresh_token=" + refreshToken;
// 請求執行
httpRequest(url, new ApiCallback<String>() {
@Override public void onSuccess(String response) { Logger.e("refreshAccessToken: " + response); // 判斷是否獲取成功,成功則去獲取用戶信息,不然提示失敗 processGetAccessTokenResult(response); } @Override public void onError(int errorCode, final String errorMsg) { Logger.e(errorMsg); showMessage("錯誤信息: " + errorMsg); // 從新請求受權 loginWeixin(WXEntryActivity.this.getApplicationContext(), GeneralAppliction.sApi); } @Override public void onFailure(IOException e) { Logger.e(e.getMessage()); showMessage("登陸失敗"); // 從新請求受權 loginWeixin(WXEntryActivity.this.getApplicationContext(), GeneralAppliction.sApi); } }); }
/**
* 獲取用戶信息
*
/
private void getUserInfo(String access_token, String openid) {
String url = "https://api.weixin.qq.com/sns/userinfo?" +
"access_token=" + access_token +
"&openid=" + openid;
httpRequest(url, new ApiCallback<String>() {
@Override public void onSuccess(String response) { // 解析獲取的用戶信息 WXUserInfo userInfo = mGson.fromJson(response, WXUserInfo.class); Logger.e("用戶信息獲取結果:" + userInfo.toString()); } @Override public void onError(int errorCode, String errorMsg) { showMessage("錯誤信息: " + errorMsg); } @Override public void onFailure(IOException e) { showMessage("獲取用戶信息失敗"); } }); }
private OkHttpClient mHttpClient = new OkHttpClient.Builder().build(); private Handler mCallbackHandler = new Handler(Looper.getMainLooper()); /** * 經過Okhttp與微信通訊 * * @param url 請求地址 * @throws Exception */ public void httpRequest(String url, final ApiCallback<String> callback) { Logger.e("url: %s", url); final Request request = new Request.Builder() .url(url) .get() .build(); mHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, final IOException e) { if (callback != null) { mCallbackHandler.post(new Runnable() { @Override public void run() { // 請求失敗,主線程回調 callback.onFailure(e); } }); } } @Override public void onResponse(Call call, final Response response) throws IOException { if (callback != null) { if (!response.isSuccessful()) { mCallbackHandler.post(new Runnable() { @Override public void run() { // 請求出錯,主線程回調 callback.onError(response.code(), response.message()); } }); } else { mCallbackHandler.post(new Runnable() { @Override public void run() { try { // 請求成功,主線程返回請求結果 callback.onSuccess(response.body().string()); } catch (final IOException e) { // 異常出錯,主線程回調 mCallbackHandler.post(new Runnable() { @Override public void run() { callback.onFailure(e); } }); } } }); } } } }); } // Api通訊回調接口 public interface ApiCallback<T> { /** * 請求成功 * * @param response 返回結果 */ void onSuccess(T response); /** * 請求出錯 * * @param errorCode 錯誤碼 * @param errorMsg 錯誤信息 */ void onError(int errorCode, String errorMsg); /** * 請求失敗 */ void onFailure(IOException e); }
集成的詳細描述就這樣,至於獲取的用戶信息,小夥伴們應該知道後續本身業務的需求,該怎麼處理了。