本人Android小白一枚,最近项目中需要用到Andorid拉起微信登录和支付,所以将踩过的坑和经验记录下来,希望能帮助到大家,有哪里写的不好的地方欢迎大家指正,感谢阅读。
移动应用接入微信官方文档:https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/Android.html
1.申请移动应用
2.集成微信登录支付
3.服务端下单实现
------------------------------------------------------我是分割线-------------------------------------------------
这里别忘了将你的WXEntryActivity注册到配置文件application节点中:
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"/>
<activity
android:name=".wxapi.WXEntryActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="true"
android:taskAffinity="你的包名"
android:launchMode="singleTask">
</activity>
WXEntryActivity类实现IWXAPIEventHandler接口,这里onResp用来接收拉起微信支付的结果通知。代码如下:
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.modelmsg.SendAuth;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
public static final String APP_ID = "移动应用的AppId";
//public static final String APP_SECRET = "移动应用的Secret";
private IWXAPI api;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
// 隐藏状态栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
api = WXAPIFactory.createWXAPI(this, APP_ID, true);
api.handleIntent(getIntent(), this);
}
@Override
public void onReq(BaseReq baseReq) {
}
@Override
public void onResp(BaseResp baseResp) {
Log.d("onResp", "onResp: " + baseResp.errCode);
switch (baseResp.errCode) {
case BaseResp.ErrCode.ERR_OK:
String code = ((SendAuth.Resp) baseResp).code; //即为所需的code
Log.d("login succes--", "code: " + code);
break;
}
}
}
WXPayEntryActivity代码如下:
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
api = WXAPIFactory.createWXAPI(this, WXEntryActivity.APP_ID);
api.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
api.handleIntent(intent, this);
}
@Override
public void onReq(BaseReq req) {
}
@Override
public void onResp(BaseResp resp) {
Log.d("WXPayEntryActivity ", "onPayFinish, errCode = " + resp.errCode);
/*if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
//
}*/
}
}
然后就在你的Activity中将移动应用注册到微信:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
// 隐藏状态栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 通过WXAPIFactory工厂,获取IWXAPI的实例
api = WXAPIFactory.createWXAPI(Android.context, null);
api.registerApp(WXEntryActivity.APP_ID);
login();
}
//微信登录核心代码
private void login(){
//拉起微信登录
SendAuth.Req req = new SendAuth.Req();
//授权域 获取用户个人信息则填写snsapi_userinfo
req.scope = "snsapi_userinfo";
//用于保持请求和回调的状态 可以任意填写
req.state = "test_login";
api.sendReq(req);
}
//微信支付核心代码
private void toPay(){
//1. 请求服务端,获取下单数据
String url = "https://www.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
//2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
Request request = new Request.Builder()
.url(url)
.get()
.build();
//3.创建一个call对象,参数就是Request请求对象
Call call = okHttpClient.newCall(request);
//4.同步调用会阻塞主线程,这边在子线程进行
new Thread(new Runnable() {
@Override
public void run() {
try {
//同步调用,返回Response,会抛出IO异常
Response response = call.execute();
String string = response.body().string();
//将返回的数据序列化
Dict data = (Dict) JSON.parse(string);
//2. 拿到数据调拉起微信支付
String appId = data.got("appid").stringValue();
String partnerId = data.got("partnerid").stringValue();
String prepayId = data.got("prepayid").stringValue();
String nonceStr = data.got("noncestr").stringValue();
String timeStamp = data.got("timestamp").stringValue();
//这里键名是官方文档和官方示例的不准确,以官方文档为准
String packageValue = data.got("package").stringValue();
String sign = data.got("sign").stringValue();
payHandler(appId, partnerId, prepayId, nonceStr, timeStamp, packageValue,sign);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
*
* @param partnerId 商户号
* @param prepayId 预支付订单号
* @param nonceStr 签名随机字符串
* @param timeStamp 签名时间戳
* @param sign 签名
*/
private void payHandler(String appId, String partnerId, String prepayId, String nonceStr, String timeStamp, String packageValue,String sign) {
// api = WXAPIFactory.createWXAPI(this, appId, false); //初始化微信api
// api = WXAPIFactory.createWXAPI(this, null); //初始化微信api
// api.registerApp(appId); //注册appid appid可以在开发平台获取
Runnable payRunnable = new Runnable() { //这里注意要放在子线程
@Override
public void run() {
PayReq request = new PayReq(); //调起微信APP的对象
//下面是设置必要的参数,也就是前面说的参数,这几个参数从何而来请看上面说明
request.appId = appId;
request.partnerId = partnerId;
request.prepayId = prepayId;
request.packageValue = packageValue;
request.nonceStr = nonceStr;
request.timeStamp = timeStamp;
request.sign = sign;
api.sendReq(request);//发送调起微信的请求
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
/**
* 微信App统一下单
* @param appid 移动应用appid
* @param mch_id 商户id
* @param pay_key 商户secret
* @param notify_url 支付通知回调地址
* @param trade_type 支付类型
* @param sign_type 签名类型
* @param body 标题
* @param out_trade_no 外部商户订单号
* @param total_fee 支付金额,微信以分为单位
* @param spbill_create_ip 终端ip
* @return
* @throws Exception
*/
public static String unifiedorder(String appid, String mch_id, String pay_key, String notify_url, String trade_type, String sign_type,
String body, String out_trade_no, String total_fee, String spbill_create_ip) throws Exception {
String nonce_str = createNoncestr();//生成随机字符串
saveNonceStr("./unifiedorderData.txt",nonce_str);
JsonObject params = new JsonObject();
params.addProperty("appid", appid);
params.addProperty("mch_id", mch_id);
params.addProperty("body", body);
params.addProperty("out_trade_no", out_trade_no);
params.addProperty("total_fee", total_fee);
params.addProperty("spbill_create_ip", spbill_create_ip);
params.addProperty("notify_url", notify_url);
params.addProperty("trade_type", trade_type);
params.addProperty("nonce_str", nonce_str);
params.addProperty("sign_type", sign_type);
//加签名
params.addProperty("sign",md5(params, sign_type, pay_key));
String xmlData = jsonToXml(params);//数组转字符串
String xml_result = _request("https://api.mch.weixin.qq.com/pay/unifiedorder","POST",xmlData);
JsonObject result_array = xmlToJson(xml_result);
if(!result_array.has("sign")) {
return result_array.get("return_msg").getAsString();
}
String unifiedorder_sign = result_array.get("sign").getAsString();
result_array.remove("sign");
String check_sing_data = md5(result_array, sign_type, pay_key);
if(!unifiedorder_sign.equals(check_sing_data)) {
return "check_sign:error!";
}
if(!result_array.get("return_code").getAsString().equals("SUCCESS")) {
return xml_result;
}
//加签
return _unifiedorder_return_data(result_array.get("prepay_id").getAsString(), sign_type, mch_id, pay_key, sign_type);
}
//生成随机字符串
public static String createNoncestr() {
String rand_char = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String str="";
for(int i=0;i<32;i++) {
str+=rand_char.charAt((int)(Math.random()*rand_char.length()));
}
return str;
}
public static void saveNonceStr(String path,String data) throws Exception {
FileWriter fileWriter = new FileWriter(path);
fileWriter.write(data);
fileWriter.close();
}
//md5签名方式
public static String md5(String text) throws Exception {
return md5(text,128);
}
public static String md5(String text,int keyLength) throws Exception {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(text.getBytes("UTF-8")); // 通过使用 update 方法处理数据,使指定的 byte数组更新摘要 (为什么需要先使用update方法 有的md5方法中怎么不使用?)
byte[] encryptStr = md.digest(); // 获得密文完成哈希计算,产生128 位的长整数
char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话,使用两个字符
int k = 0; // 表示转换结果中对应的字符位置
for (int i = 0; i < 16; i++) { // 从第一个字节开始,对每一个字节,转换成 16 进制字符的转换
byte byte0 = encryptStr[i]; // 取第 i 个字节
str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移
str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
}
return new String(str); // 换后的结果转换为字符串
}
//json转xml
public static String jsonToXml(JsonObject arr)
{
String xml = "" ;
for(Entry<String, JsonElement> entry : arr.entrySet()) {
xml += "<" +entry.getKey()+ ">" +entry.getValue().getAsString()+ "" +entry.getKey()+ ">";
}
xml += "";
return xml;
}
//xml转json
public static JsonObject xmlToJson(String str) throws Exception {
JsonObject map = new JsonObject();
//
Document document = DocumentHelper.parseText(str);
for (Element child : document.getRootElement().elements()) {
map.addProperty(child.getName(), child.getStringValue());
}
return map;
}
public static String _request(String url, String method, String data) throws Exception {
HttpRequestBase request;
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
if (data != null) {
StringEntity entity = new StringEntity(data, "utf-8");
// entity.setContentEncoding("utf-8");
httpPost.setEntity(entity);
}
request = httpPost;
request.addHeader("Content-Type", "application/json; charset=\"utf-8\"");
CloseableHttpResponse response = httpClient.execute(request);
return EntityUtils.toString(response.getEntity(), "utf-8");
}
//加签,这里注意加签时候的键名最好不要改,否则客户端的开发人员拿到这个直接去拉起微信支付的话需要重新签名
private static String _unifiedorder_return_data(String prepay_id,String appid, String mch_id, String pay_key, String sign_type) throws Exception {
Long timeStamp = new Date().getTime();
String nonceStr = createNoncestr();//生成字符串
JsonObject sign = new JsonObject();
sign.addProperty("appid", appid);
sign.addProperty("partnerid", mch_id);
sign.addProperty("prepayid", prepay_id);
sign.addProperty("package", "Sign=WXPay");
sign.addProperty("noncestr", nonceStr);
sign.addProperty("timestamp", String.valueOf(timeStamp));
sign.addProperty("sign", md5(sign, sign_type, pay_key));//得到签名
// sign.addProperty("out_trade_no", outTradeNo);
return sign.toString();//转成字符串
}
至此,整个Android集成微信登录和支付的流程就走完啦,看完觉得写的好不错别忘记加个关注哟~