**
Android 微信支付宝授权
**
最近项目中要实现微信支付宝授权获取用户信息以及支付,在网上查了很多资料,项目中将两个平台的收取与支付写在了一起,记录一下以便以后使用时查看。
1. 微信&支付宝sdk下载
一、微信平台&支付宝平台申请应用
去微信开放平台(默认你已经注册了微信开发平台账号,微信支付需要开发者资质验证好像是300大洋,一般由公司提供账号)创建应用,如下图,在管理中心创建应用,按提示操作进行就行,没什么难的
应用通过以后在 开发信息 中填上你应用的应用包名和应用签名
填写的包名一定要跟你要集成的APP的包名一致,也就是你项目下,AndroidManifest文件下的pakage或者build.gradle文件下的applicationid
AndroidManifest:
app->build.gradle:
获取应用签名:
1、微信开放平台下载开发工具包(SDK)和签名工具
A==/dissolve/70)
2、将下载的“签名工具”APK,安装到手机。在该手机上安装你打包的应用的APK并运行,通过签名生成工具输入包名get signature获取应用签名,填写到微信开发平台,平台会分配给你AppID和AppSecret。
支付宝应用申请与微信类似,得到PID,APPID和RSA2_PRIVATE
支付宝开放平台下载sdk
官网地址下载sdk和demo
二、项目中使用
1、将wechat-sdk-android-with-mta-1.0.2.jar和alipaySdk-20160223.jar 拷贝到我们工程的libs下,并添加到依赖中
Android Studio环境下:已改用gradle形式,使用gradle来编译、更新微信SDK。
在build.gradle文件中,添加如下依赖即可:
dependencies {
compile ‘com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+’
}
或
dependencies {
compile ‘com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+’
}
2、配置AndroidManifest添加如下代码:
权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
//微信
<activity
android:name=".wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Translucent">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="微信给你的AppID" />
</intent-filter>
</activity>
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="wx8d024c5351b07056" />
</intent-filter>
</activity>
//支付宝
<!-- alipay sdk begin -->
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name="com.alipay.sdk.app.H5AuthActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" />
<!-- alipay sdk end -->
2、微信需要在项目中有回调类处理微信返回的信息,必须在你app包名下面新建文件夹wxapi,然后新建类名必须为:授权: WXEntryActivity,支付:WXPayEntryActivity
项目中使用微信&支付宝请求授权的代码:
public class AuthUtils {
/** 支付宝支付业务:入参app_id */
public static final String APPID = "你的APPID";
/** 支付宝账户登录授权业务:入参pid值 */
public static final String PID = "你的PID";
/** 支付宝账户登录授权业务:入参target_id值 */
public static final String TARGET_ID = "1";
public static final String RSA2_PRIVATE = "你的RSA2_PRIVATE ";
public static final String RSA_PRIVATE = "";
private static Context mContext;
private static final int SDK_AUTH_FLAG=1002;
public static String userId="";
public static String authCode="";
private static AliAuthBack mAliAuthBack;
/**
* 调用支付宝的授权
* @param content 后台传过来的数据
* @param context 上下文
*/
public static void setAliAuth(final String content,Context context){
mContext=context;
//检测是否安装支付宝
Uri uri=Uri.parse("alipays://platformapi/startApp");
Intent intent=new Intent(Intent.ACTION_VIEW,uri);
ComponentName componentName=intent.resolveActivity(context.getPackageManager());
//确认安装支付宝后进行授权接口调用
if(componentName!=null){
boolean rsa2 = (RSA2_PRIVATE.length() > 0);
Map<String, String> authInfoMap = OrderInfoUtil2_0.buildAuthInfoMap(PID, APPID, TARGET_ID, rsa2);
String info = OrderInfoUtil2_0.buildOrderParam(authInfoMap);
String privateKey = rsa2 ? RSA2_PRIVATE : RSA_PRIVATE;
String sign = OrderInfoUtil2_0.getSign(authInfoMap, privateKey, rsa2);
final String authInfo = info + "&" + sign;
//异步处理
Runnable authRunnable=new Runnable() {
@Override
public void run() {
//构造AuthTask对象
AuthTask authTask=new AuthTask((Activity)mContext);
//调用授权接口,获取授权结果
Map<String,String >result=authTask.authV2(authInfo,true);
Message msg=new Message();
msg.what=SDK_AUTH_FLAG;
msg.obj=result;
mHandler.sendMessage(msg);
}
};
//必须异步处理
Thread authThread=new Thread(authRunnable);
authThread.start();
}else{
ToastUtil.show("请您先安装支付宝");
}
}
private static Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case SDK_AUTH_FLAG:
AuthResult authResult = new AuthResult((Map<String, String>) msg.obj, true);
String resultStatus = authResult.getResultStatus();
// 判断resultStatus 为“9000”且result_code
// 为“200”则代表授权成功,具体状态码代表含义可参考授权接口文档
if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) {
// 获取alipay_open_id,调支付时作为参数extern_token 的value
// 传入,则支付账户为该授权账户
if(mAliAuthBack!=null){
mAliAuthBack.authInfo(authResult.getAuthCode(),authResult.getUserId());
}
// Toast.makeText(mContext, "授权成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT)
// .show();
Toast.makeText(mContext, "授权成功", Toast.LENGTH_SHORT)
.show();
} else {
// 其他状态值则为授权失败
Toast.makeText(mContext, "授权失败", Toast.LENGTH_SHORT).show();
}
break;
}
}
};
private void setAuthCode(String authCode){
this.authCode=authCode;
}
public void setAliAuthBack(AliAuthBack back){
this.mAliAuthBack=back;
}
public interface AliAuthBack{
void authInfo(String authCode,String userId);
}
public static void WechatAuth(Context context){
final IWXAPI api= WXAPIFactory.createWXAPI(context,null);
api.registerApp(Const.WeChat_APPID);
if(!api.isWXAppInstalled()){
ToastUtil.show("请您先安装微信");
}else {
final SendAuth.Req req=new SendAuth.Req();
req.scope="snsapi_userinfo";
req.state="wechat_sdk_demo_test";
api.sendReq(req);
}
}
}
支付宝:
1、判断是否安装支付宝 2、发送授权请求 这里必须要异步处理 3、支付宝返回的用户信息 这里利用回调AliAuthBack.authInfo() 将信息返回给Activity;
项目中定义了对象AuthResult用于接受支付宝的返回信息;
AuthResult 代码:
public class AuthResult {
private String resultStatus;
private String result;
private String memo;
private String resultCode;
private String authCode;
private String alipayOpenId;
private String userId;
public AuthResult(Map<String, String> rawResult, boolean removeBrackets) {
if (rawResult == null) {
return;
}
for (String key : rawResult.keySet()) {
if (TextUtils.equals(key, "resultStatus")) {
resultStatus = rawResult.get(key);
} else if (TextUtils.equals(key, "result")) {
result = rawResult.get(key);
} else if (TextUtils.equals(key, "memo")) {
memo = rawResult.get(key);
}
}
String[] resultValue = result.split("&");
for (String value : resultValue) {
if (value.startsWith("alipay_open_id")) {
alipayOpenId = removeBrackets(getValue("alipay_open_id=", value), removeBrackets);
continue;
}
if (value.startsWith("auth_code")) {
authCode = removeBrackets(getValue("auth_code=", value), removeBrackets);
continue;
}
if (value.startsWith("result_code")) {
resultCode = removeBrackets(getValue("result_code=", value), removeBrackets);
continue;
}
if (value.startsWith("user_id")) {
userId = removeBrackets(getValue("user_id=", value), removeBrackets);
continue;
}
}
}
private String removeBrackets(String str, boolean remove) {
if (remove) {
if (!TextUtils.isEmpty(str)) {
if (str.startsWith("\"")) {
str = str.replaceFirst("\"", "");
}
if (str.endsWith("\"")) {
str = str.substring(0, str.length() - 1);
}
}
}
return str;
}
@Override
public String toString() {
return "resultStatus={" + resultStatus + "};memo={" + memo + "};result={" + result + "}";
}
private String getValue(String header, String data) {
return data.substring(header.length(), data.length());
}
/**
* @return the resultStatus
*/
public String getResultStatus() {
return resultStatus;
}
/**
* @return the memo
*/
public String getMemo() {
return memo;
}
/**
* @return the result
*/
public String getResult() {
return result;
}
/**
* @return the resultCode
*/
public String getResultCode() {
return resultCode;
}
/**
* @return the authCode
*/
public String getAuthCode() {
return authCode;
}
/**
* @return the alipayOpenId
*/
public String getAlipayOpenId() {
return alipayOpenId;
}
/**
* @return the userId
*/
public String getUserId() {
return userId;
}
}
微信:
1、判断是否安装微信 2、发送授权请求 3、用户操作后回调WXEntryActivity的onResp方法。
类WXEntryActivity代码如下:
基本时按照官方demo做了一点修改
其中 Const.WeChat_APPID,Const.WeChat_APP_SECRET 就是微信分配的 APPID和AppSecret
这些信息最好是通过服务端获取,在客户端会有安全问题。
public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.entry);
api = WXAPIFactory.createWXAPI(this, Const.WeChat_APPID, false);//微信的appId
try {
api.handleIntent(getIntent(), this);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
api.handleIntent(intent, this);
finish();
}
//微信发送请求到第三方应用时,会回调到该方法
@Override
public void onReq(BaseReq req) {
switch (req.getType()) {
case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX:
goToGetMsg();
break;
case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX:
goToShowMsg((ShowMessageFromWX.Req) req);
break;
default:
break;
}
}
//第三方应用发送到微信的请求处理后的响应结果,会回调到该方法
@Override
public void onResp(BaseResp resp) {
int result = 0;
//Toast.makeText(this, "baseresp.getType = " + resp.getType(), Toast.LENGTH_SHORT).show();
switch (resp.errCode) {
case BaseResp.ErrCode.ERR_OK:
result = R.string.errcode_success;
//微信分享
if (resp.getType() == ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX)
this.finish();
else{
String code = ((SendAuth.Resp) resp).code;
//获取用户信息
getAccessToken(code);
}
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
result = R.string.errcode_cancel;
this.finish();
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
result = R.string.errcode_deny;
break;
case BaseResp.ErrCode.ERR_UNSUPPORT:
result = R.string.errcode_unsupported;
break;
default:
result = R.string.errcode_unknown;
break;
}
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
}
private void goToGetMsg() {
}
private void goToShowMsg(ShowMessageFromWX.Req showReq) {
}
private void getAccessToken(String code) {
//获取授权
StringBuffer loginUrl = new StringBuffer();
loginUrl.append("https://api.weixin.qq.com/sns/oauth2/access_token")
.append("?appid=")
.append(Const.WeChat_APPID)
.append("&secret=")
.append(Const.WeChat_APP_SECRET)
.append("&code=")
.append(code)
.append("&grant_type=authorization_code");
OkHttpUtils.ResultCallback<String> resultCallback = new OkHttpUtils.ResultCallback<String>() {
@Override
public void onSuccess(String response) {
String access = null;
String openId = null;
try {
JSONObject jsonObject = new JSONObject(response);
access = jsonObject.getString("access_token");
openId = jsonObject.getString("openid");
} catch (Exception e) {
e.printStackTrace();
}
//获取个人信息
String getUserInfo = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access + "&openid=" + openId;
OkHttpUtils.ResultCallback<String> reCallback = new OkHttpUtils.ResultCallback<String>() {
@Override
public void onSuccess(String response) {
String nickName = null;
String sex = null;
String city = null;
String province = null;
String country = null;
String headimgurl = null;
WechatUserInfo info = new WechatUserInfo();
try {
JSONObject jsonObject = new JSONObject(response);
String deviceId= AppBaseApplication.getInstance().getDeviceInfo().deviceId;
info.setMemberID(deviceId);
info.setOpenId(jsonObject.getString("openid"));
info.setNickName(jsonObject.getString("nickname"));
info.setSex(jsonObject.getString("sex"));
info.setCountry(jsonObject.getString("country"));
info.setProvince(jsonObject.getString("province"));
info.setCity(jsonObject.getString("city"));
info.setHeadimgurl(jsonObject.getString("headimgurl"));
info.setUnionid(jsonObject.getString("unionid"));
//传到Activity
/*Intent i= new Intent(WXEntryActivity.this,PutForwardBindActivity.class);
i.putExtra("userInfo",info);
startActivity(i);*/
//添加到数据库
WechatUserInfoDaoImpl wechatImpl = new WechatUserInfoDaoImpl(HsApplication.getInstance());
wechatImpl.insert(info);
finish();
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Exception e) {
ToastUtil.show(WXEntryActivity.this,"获取信息失败");
finish();
}
};
OkHttpUtils.get(getUserInfo.toString(), reCallback);
}
@Override
public void onFailure(Exception e) {
ToastUtil.show(WXEntryActivity.this,"登录失败");
finish();
}
};
OkHttpUtils.get(loginUrl.toString(), resultCallback);
}
}
重点注意onResp这个方法是应用发送到微信的请求处理后的响应结果,会回调到该方法
1、判断 resp.errCode的值 成功会返回并且带上授权临时票据code参数;
2、通过code参数加上AppID和AppSecret等,通过API调用获得access_token;
3、通过access_token进行接口调用,获取用户基本数据信息。
这里获取到用户基本信息后我这里存到了本地数据库(使用OrmLite框架,参考https://www.cnblogs.com/itgungnir/p/6210949.html
),可以用其他方式返回微信的个人信息。
OkHttpUtils的代码:
public class OkHttpUtils {
private static OkHttpUtils mInstance;
private OkHttpClient mOkHttpClient;
private Handler mDelivery;
protected static Retrofit mRetrofit;
private OkHttpUtils() {
mOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
mDelivery = new Handler(Looper.getMainLooper());
}
private synchronized static OkHttpUtils getmInstance() {
if (mInstance == null) {
mInstance = new OkHttpUtils();
}
return mInstance;
}
private void getRequest(String url, final ResultCallback callback) {
final Request request = new Request.Builder().url(url).build();
deliveryResult(callback, request);
}
private void postRequest(String url, final ResultCallback callback, List<Param> params) {
Request request = buildPostRequest(url, params);
deliveryResult(callback, request);
}
/**
* 处理结果
* @param callback
* @param request
*/
private void deliveryResult(final ResultCallback callback, Request request) {
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
sendFailCallback(callback, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
String str = response.body().string();
if (callback.mType == String.class) {
/**
* 返回字符串
*/
sendSuccessCallBack(callback, str);
} else {
/**
* 这里处理解析返回对象
*/
Object object = JSON.parseObject(str, callback.mType);
sendSuccessCallBack(callback, object);
}
} catch (final Exception e) {
// LogUtils.e(TAG, "convert json failure", e);
sendFailCallback(callback, e);
}
}
});
}
private void sendFailCallback(final ResultCallback callback, final Exception e) {
mDelivery.post(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onFailure(e);
}
}
});
}
private void sendSuccessCallBack(final ResultCallback callback, final Object obj) {
mDelivery.post(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onSuccess(obj);
}
}
});
}
private Request buildPostRequest(String url, List<Param> params) {
FormBody.Builder builder= new FormBody.Builder();
for (Param param : params) {
builder.add(param.key, param.value);
}
RequestBody requestBody = builder.build();
return new Request.Builder().url(url).post(requestBody).build();
}
/**********************对外接口************************/
/**
* get请求
* @param url 请求url
* @param callback 请求回调
*/
public static void get(String url, ResultCallback callback) {
getmInstance().getRequest(url, callback);
}
/**
* post请求
* @param url 请求url
* @param callback 请求回调
* @param params 请求参数
*/
public static void post(String url, final ResultCallback callback, List<Param> params) {
getmInstance().postRequest(url, callback, params);
}
/**
* http请求回调类,回调方法在UI线程中执行
* @param <T>
*/
public static abstract class ResultCallback<T> {
Type mType;
public ResultCallback(){
mType = getSuperclassTypeParameter(getClass());
}
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return parameterized.getActualTypeArguments()[0];
}
/**
* 请求成功回调
* @param response
*/
public abstract void onSuccess(T response);
/**
* 请求失败回调
* @param e
*/
public abstract void onFailure(Exception e);
}
/**
* post请求参数类 这里可以根据项目抽取成泛型
*/
public static class Param {
String key;
String value;
public Param() {
}
public Param(String key, String value) {
this.key = key;
this.value = value;
}
}
}