轉載須要著名出處:html
http://blog.csdn.net/lowprofile_coding/article/details/78004224
以前寫過微信登陸分享支付初版:java
http://blog.csdn.net/lowprofile_coding/article/details/48086381
大部分的app都有接入第三方sdk的需求。例如第三方登陸須要接入微信、QQ、微博。第三方支付須要接入微信、支付寶、銀聯。android
這些我都有使用過,都有使用過他們的sdk,感受最麻煩的就是微信,不能直接調試,得用正式的簽名進行簽名才能調試。還有他們官方的demo也是跑不起來的,由於沒有簽名文件。須要注意的地方也不少。git
微信sdk如今支持Android Studio在線引用了,以前都是添加jar的方法。須要訪問微信的接口獲取用戶信息,因此把咱們以前封裝的okhttp也一塊兒在線引用。okhttp須要在自定義的Application中初始化這個我就不貼代碼了。以前已經講過不少次。在app/build.gradle文件dependencies標籤中加入如下兩行代碼:github
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+' compile 'com.ansen.http:okhttpencapsulation:1.0.1'
須要用到網絡,因此在AndroidManifest.xml文件中加入網絡權限:web
<uses-permission android:name="android.permission.INTERNET" />
activity_main.xml算法
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="登陸以後信息在這裏顯示"/> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_nickname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="暱稱:"/> <TextView android:id="@+id/tv_age" android:layout_below="@+id/tv_nickname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="年齡:"/> </RelativeLayout> <Button android:id="@+id/btn_login" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="微信登陸"/> <Button android:id="@+id/btn_share_friend_circle" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="分享到朋友圈"/> <Button android:id="@+id/btn_share_friend" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="分享給好友"/> <Button android:id="@+id/btn_pay" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="微信支付"/> </LinearLayout>
佈局文件很簡單,就LinearLayout裏面放了幾個TextView,跟幾個按鈕。json
WeiXin.java 用於EventBus來傳送消息,微信sdk有個很奇怪的地方,就是無論登陸、分享、支付以後都得用一個Activity來接收,因此咱們還得從接收的那個activity把結果信息經過EventBus傳遞給MainActivity。雖然用廣播也能實現,可是我的喜歡用EventBus,使用靈活。簡單輕量。api
public class WeiXin { private int type;//1:登陸 2.分享 3:微信支付 private int errCode;//微信返回的錯誤碼 private String code;//登陸成功纔會有的code public WeiXin() { } public WeiXin(int type,int errCode, String code) { this.type = type; this.errCode=errCode; this.code = code; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public int getErrCode() { return errCode; } public void setErrCode(int errCode) { this.errCode = errCode; } }
Constant.java 常量類,微信appid跟secret的值用兩個常量保存。爲了保護隱私這兩個值我已經修改過。數組
public class Constant { public static String WECHAT_APPID="wxda6db2aec81389af"; public static String WECHAT_SECRET="8fed5a2d510022587ef8a6194c965be3"; }
MainActivity.java 所有代碼貼出來比較亂,暫時貼出MainActivity部分代碼。
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private IWXAPI wxAPI; private TextView tvNickname,tvAge; public static final int IMAGE_SIZE=32768;//微信分享圖片大小限制 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register(this);//註冊 wxAPI = WXAPIFactory.createWXAPI(this,Constant.WECHAT_APPID,true); wxAPI.registerApp(Constant.WECHAT_APPID); findViewById(R.id.btn_login).setOnClickListener(this); findViewById(R.id.btn_share_friend_circle).setOnClickListener(this); findViewById(R.id.btn_share_friend).setOnClickListener(this); findViewById(R.id.btn_pay).setOnClickListener(this); tvNickname= (TextView) findViewById(R.id.tv_nickname); tvAge=(TextView) findViewById(R.id.tv_age); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn_login://微信登陸 login(); break; case R.id.btn_share_friend_circle://微信分享到朋友圈 share(true); break; case R.id.btn_share_friend://微信分享給朋友 share(false); break; case R.id.btn_pay://微信支付 // 先去服務器獲取支付信息,返回一個WeiXinPay對象,而後調用pay方法 showToast("微信支付須要服務器支持"); break; } } /** * 這裏用到的了EventBus框架 * @param weiXin */ @Subscribe public void onEventMainThread(WeiXin weiXin){ Log.i("ansen","收到eventbus請求 type:"+weiXin.getType()); if(weiXin.getType()==1){//登陸 getAccessToken(weiXin.getCode()); }else if(weiXin.getType()==2){//分享 switch (weiXin.getErrCode()){ case BaseResp.ErrCode.ERR_OK: Log.i("ansen", "微信分享成功....."); break; case BaseResp.ErrCode.ERR_USER_CANCEL://分享取消 Log.i("ansen", "微信分享取消....."); break; case BaseResp.ErrCode.ERR_AUTH_DENIED://分享被拒絕 Log.i("ansen", "微信分享被拒絕....."); break; } }else if(weiXin.getType()==3){//微信支付 if(weiXin.getErrCode()==BaseResp.ErrCode.ERR_OK){//成功 Log.i("ansen", "微信支付成功....."); } } } .......... public void showToast(String message){ Toast.makeText(this,message,Toast.LENGTH_LONG).show(); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this);//取消註冊 } }
微信登陸
微信登陸流程有如下三個步驟:
當咱們點擊登陸按鈕的時候,調用的是login方法。這個方法就在MainActivity裏面。就是給微信發起一個登陸請求,彈出一個受權界面。
public void login(){ SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = String.valueOf(System.currentTimeMillis()); wxAPI.sendReq(req); }
在你的包名相應目錄下新建一個wxapi目錄,而後在wxapi目錄下新增一個WXEntryActivity類,用來接收登陸受權以及分享時微信的回調信息。這個類繼承自Activity,須要實現IWXAPIEventHandler接口。
package com.ansen.shoenet.wxapi; public class WXEntryActivity extends Activity implements IWXAPIEventHandler { private IWXAPI wxAPI; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); wxAPI = WXAPIFactory.createWXAPI(this,Constant.WECHAT_APPID,true); wxAPI.registerApp(Constant.WECHAT_APPID); wxAPI.handleIntent(getIntent(), this); } @Override protected void onNewIntent(Intent intent){ super.onNewIntent(intent); wxAPI.handleIntent(getIntent(),this); Log.i("ansen","WXEntryActivity onNewIntent"); } @Override public void onReq(BaseReq arg0) { Log.i("ansen","WXEntryActivity onReq:"+arg0); } @Override public void onResp(BaseResp resp){ if(resp.getType()== ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX){//分享 Log.i("ansen","微信分享操做....."); WeiXin weiXin=new WeiXin(2,resp.errCode,""); EventBus.getDefault().post(weiXin); }else if(resp.getType()==ConstantsAPI.COMMAND_SENDAUTH){//登錄 Log.i("ansen", "微信登陸操做....."); SendAuth.Resp authResp = (SendAuth.Resp) resp; WeiXin weiXin=new WeiXin(1,resp.errCode,authResp.code); EventBus.getDefault().post(weiXin); } finish(); } }
onCreate、onNewIntent、onReq這三個方法是固定寫法。onResp方法接收微信結果信息,首先判斷類型,根據不一樣的類型去封裝WeiXin對象,若是是登陸操做,把code傳入進去,而後把封裝好的WeiXin對象經過EventBus發送出去。MainActivity的onEventMainThread方法就會接收到這個消息。最後調用finish關閉當前的activity。
WXEntryActivity記得在AndroidManifest.xml中註冊
<activity android:exported="true" android:name=".wxapi.WXEntryActivity"/>
繼續回到首頁的onEventMainThread,若是登陸類型調用getAccessToken(),而且傳入code。根據code獲取access_token,這個url是微信公開的,須要傳入三個參數,appid、secret、code。請求成功以後會返回access_token跟openid等信息。
public void getAccessToken(String code){ String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + "appid="+Constant.WECHAT_APPID+"&secret="+Constant.WECHAT_SECRET+ "&code="+code+"&grant_type=authorization_code"; HTTPCaller.getInstance().get(WeiXinToken.class, url, null, new RequestDataCallback<WeiXinToken>() { @Override public void dataCallback(WeiXinToken obj) { if(obj.getErrcode()==0){//請求成功 getWeiXinUserInfo(obj); }else{//請求失敗 showToast(obj.getErrmsg()); } } }); }
獲取到access_token跟openid以後繼續調用getWeiXinUserInfo方法獲取用戶信息。這樣就能取到當前微信app登陸的用戶一些信息。有暱稱、年齡、頭像地址、語言等基本信息。在企業開發中,到了這一步就能夠拿着這些信息調用本身服務器的登陸接口。固然咱們這邊就把暱稱跟年齡給TextView顯示下。
public void getWeiXinUserInfo(WeiXinToken weiXinToken){ String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+ weiXinToken.getAccess_token()+"&openid="+weiXinToken.getOpenid(); HTTPCaller.getInstance().get(WeiXinInfo.class, url, null, new RequestDataCallback<WeiXinInfo>() { @Override public void dataCallback(WeiXinInfo obj) { tvNickname.setText("暱稱:"+obj.getNickname()); tvAge.setText("年齡:"+obj.getAge()); Log.i("ansen","頭像地址:"+obj.getHeadimgurl()); } }); }
WeiXinToken跟WeiXinInfo這兩個實體類就不貼代碼了,WeiXinToken用來映射獲取訪問token接口返回的json。WeiXinInfo用來映射獲取用戶接口返回的json。
微信分享
分享有兩種分享到朋友圈跟分享給好友,統一調用share方法。傳入一個boolean類型來判斷是否分享到朋友圈。
public void share(boolean friendsCircle){ WXWebpageObject webpage = new WXWebpageObject(); webpage.webpageUrl = "www.baidu.com";//分享url WXMediaMessage msg = new WXMediaMessage(webpage); msg.title = "分享標題"; msg.description = "分享描述"; msg.thumbData =getThumbData();//封面圖片byte數組 SendMessageToWX.Req req = new SendMessageToWX.Req(); req.transaction = String.valueOf(System.currentTimeMillis()); req.message = msg; req.scene = friendsCircle ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession; wxAPI.sendReq(req); }
分享內容有不少格式,分享圖片、分享視頻、分享消息。咱們這邊就分享消息爲例,也是分享比較常見的格式。首先new一個WXWebpageObject對象,設置標題、內容、打開連接、封面等。最後調用wxAPI的sendReq放鬆一個請求。
分享跟登陸同樣,都會回調WXEntryActivity,而後又把分享結果發送給MainActivity.onEventMainThread方法。
支付
支付首先須要請求咱們本身的服務器,獲取支付信息。獲取成功以後調用pay方法。
public void pay(WeiXinPay weiXinPay){ PayReq req = new PayReq(); req.appId = Constant.WECHAT_APPID;//appid req.nonceStr=weiXinPay.getNoncestr();//隨機字符串,不長於32位。推薦隨機數生成算法 req.packageValue=weiXinPay.getPackage_value();//暫填寫固定值Sign=WXPay req.sign=weiXinPay.getSign();//簽名 req.partnerId=weiXinPay.getPartnerid();//微信支付分配的商戶號 req.prepayId=weiXinPay.getPrepayid();//微信返回的支付交易會話ID req.timeStamp=weiXinPay.getTimestamp();//時間戳 wxAPI.registerApp(Constant.WECHAT_APPID); wxAPI.sendReq(req); }
weiXinPay的值應該是咱們從本身服務器獲取的,而後把返回信息封裝到PayReq對象中,最後調用wxAPI的sendReq方法發起請求。
在wxapi目錄下新增一個WXPayEntryActivity類,這個類跟WXEntryActivity同級,用來接收微信支付的回調信息。這個類繼承自Activity,須要實現IWXAPIEventHandler接口。
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { private IWXAPI wxAPI; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); wxAPI = WXAPIFactory.createWXAPI(this, Constant.WECHAT_APPID); wxAPI.handleIntent(getIntent(), this); } @Override protected void onNewIntent(Intent intent){ super.onNewIntent(intent); setIntent(intent); wxAPI.handleIntent(intent, this); } @Override public void onReq(BaseReq baseReq) {} @Override public void onResp(BaseResp resp) { Log.i("ansen", "微信支付回調 返回錯誤碼:"+resp.errCode+" 錯誤名稱:"+resp.errStr); if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX){//微信支付 WeiXin weiXin=new WeiXin(3,resp.errCode,""); EventBus.getDefault().post(weiXin); } finish(); } }
其餘方法都是固定寫法,在onResp中判斷若是是微信登陸,就封裝一個WeiXin對象,而後發送EventBus請求。這樣MainActivity的onEventMainThread就會接收到這個WeiXin對象。
WXPayEntryActivity記得在AndroidManifest.xml中註冊。
<activity android:exported="true" android:name=".wxapi.WXPayEntryActivity"/>
項目結構圖以下所示,從圖中咱們看到軟件包名是com.ansen.shoenet。接收微信登陸支付返回的Activity的包名必須是com.ansen.shoenet.wxapi。兩個activity的名字也是固定寫法。
微信登陸分享支付都有一個簽名驗證,這個很麻煩,致使每次調試都須要從新簽名。
首先用android studio生成一個正式的簽名文件,簽名文件是.jks結尾的,這個簽名文件是你之後打線上包一直要用到的。而後用這個簽名文件生成apk。這個時候咱們的app就有了正式簽名。把正式簽名的apk發送到手機上進行安裝。
而且下載一個簽名生成工具安裝,這個工具用於獲取安裝到手機的第三方應用簽名的apk包。微信官方下載地址:
https://res.wx.qq.com/open/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android2.apk
以上兩個app都安裝好了以後打開從微信下載的那個app,軟件名字叫「GenSignature」,有一個輸入框,輸入咱們軟件的包名,點擊Get Signature按鈕.效果圖以下:
把那行綠色的16進制數炒下來保存到txt文本中。
官網地址:
https://open.weixin.qq.com/
在微信sdk首頁,有個管理中心點擊以後默認就是移動應用,若是尚未建立移動應用就先建立一個,若是有了就點擊當前的應用後面的查看按鈕,就會進入應用詳細界面。
在應用詳細界面一直往下滾動,滾到最底部有個開發信息。點擊修改,進入修改界面,在修改界面滾動到最下面,效果圖以下所示:
首先咱們在Android應用這裏打上勾,而後填寫應用簽名,這個簽名都是我以前要大家保存到記事本上的那個值,包名就是app包名。點擊保存。
登陸以後效果圖以下:
分享到朋友圈以下:
分享給朋友:
微信支付無法測試,由於須要服務器支持。
我這偏文章只是針對如今微信的sdk版本接入,可是sdk是有可能變化的,版本變化、接口變化等。因此建議你們仍是以官方文檔爲主。個人文章提供參考。
移動應用微信登陸開發指南
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317851&token=219192a54f13e8e7011ced8e4ce5b36b699629c4&lang=zh_CN
Android微信支付開發手冊
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317784&token=219192a54f13e8e7011ced8e4ce5b36b699629c4&lang=zh_CN
接入微信sdk有不少須要注意的地方,這裏咱們最後再來作一個總結。
大家直接運行個人demo是不行的,由於大家沒有的jks文件,無法簽名,而且源碼中的appid跟secret被我修改過了,是不能使用的,可是大家可能又想看運行效果,因此我在項目下建了個apk文件夾,裏面放了一個能夠測試微信登陸分享的apk安裝包。
若是你想第一時間看個人後期文章,掃碼關注公衆號,每週不按期推送Android開發實戰教程文章...
Android開發666 - 安卓開發技術分享 掃描二維碼加關注