添加微信支付测试窗口
This commit is contained in:
@@ -69,6 +69,10 @@ dependencies {
|
|||||||
api 'io.github.medyo:android-about-page:2.0.0'
|
api 'io.github.medyo:android-about-page:2.0.0'
|
||||||
// 网络连接类库
|
// 网络连接类库
|
||||||
api 'com.squareup.okhttp3:okhttp:4.4.1'
|
api 'com.squareup.okhttp3:okhttp:4.4.1'
|
||||||
|
// OkHttp网络请求
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp:3.14.9'
|
||||||
|
// FastJSON解析
|
||||||
|
implementation 'com.alibaba:fastjson:1.2.76'
|
||||||
|
|
||||||
// AndroidX 类库
|
// AndroidX 类库
|
||||||
api 'androidx.appcompat:appcompat:1.1.0'
|
api 'androidx.appcompat:appcompat:1.1.0'
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#Created by .winboll/winboll_app_build.gradle
|
||||||
#Sat Jan 03 03:15:16 GMT 2026
|
#Sun Jan 04 09:03:20 GMT 2026
|
||||||
stageCount=9
|
stageCount=9
|
||||||
libraryProject=
|
libraryProject=
|
||||||
baseVersion=15.11
|
baseVersion=15.11
|
||||||
publishVersion=15.11.8
|
publishVersion=15.11.8
|
||||||
buildCount=2
|
buildCount=5
|
||||||
baseBetaVersion=15.11.9
|
baseBetaVersion=15.11.9
|
||||||
|
|||||||
@@ -280,6 +280,8 @@
|
|||||||
|
|
||||||
<activity android:name="cc.winboll.studio.winboll.unittest.TestWeWorkSpecSDK"/>
|
<activity android:name="cc.winboll.studio.winboll.unittest.TestWeWorkSpecSDK"/>
|
||||||
|
|
||||||
|
<activity android:name="cc.winboll.studio.winboll.activities.WXPayActivity"/>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -16,8 +16,8 @@ import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
|
|||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.winboll.R;
|
import cc.winboll.studio.winboll.R;
|
||||||
import cc.winboll.studio.winboll.activities.SettingsActivity;
|
import cc.winboll.studio.winboll.activities.SettingsActivity;
|
||||||
|
import cc.winboll.studio.winboll.activities.WXPayActivity;
|
||||||
import cc.winboll.studio.winboll.fragments.BrowserFragment;
|
import cc.winboll.studio.winboll.fragments.BrowserFragment;
|
||||||
import cc.winboll.studio.winboll.unittest.TestWeWorkSpecSDK;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class MainActivity extends DrawerFragmentActivity {
|
public class MainActivity extends DrawerFragmentActivity {
|
||||||
@@ -149,8 +149,8 @@ public class MainActivity extends DrawerFragmentActivity {
|
|||||||
}
|
}
|
||||||
} else if (nItemId == R.id.item_settings) {
|
} else if (nItemId == R.id.item_settings) {
|
||||||
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), SettingsActivity.class);
|
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), SettingsActivity.class);
|
||||||
} else if (nItemId == R.id.item_testweworkspecsdk) {
|
} else if (nItemId == R.id.item_wxpayactivity) {
|
||||||
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), TestWeWorkSpecSDK.class);
|
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), WXPayActivity.class);
|
||||||
} else if (nItemId == cc.winboll.studio.libaes.R.id.item_about) {
|
} else if (nItemId == cc.winboll.studio.libaes.R.id.item_about) {
|
||||||
Intent intent = new Intent(getApplicationContext(), AboutActivity.class);
|
Intent intent = new Intent(getApplicationContext(), AboutActivity.class);
|
||||||
APPInfo appInfo = genDefaultAPPInfo();
|
APPInfo appInfo = genDefaultAPPInfo();
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package cc.winboll.studio.winboll;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付配置类
|
||||||
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
|
* @Date 2026/01/07
|
||||||
|
*/
|
||||||
|
public class WxPayConfig {
|
||||||
|
// ========== 核心修改点:替换为你的服务端地址 ==========
|
||||||
|
// 服务端IP/域名 + 端口(Docker部署的服务端,需确保安卓端可访问)
|
||||||
|
public static final String BASE_URL = "https://wxpay.winboll.cc";
|
||||||
|
|
||||||
|
// 统一下单接口路径(对应服务端的测试接口)
|
||||||
|
public static final String CREATE_ORDER_URL = BASE_URL + "/pay/createOrder";
|
||||||
|
|
||||||
|
// 订单查询接口路径
|
||||||
|
public static final String QUERY_ORDER_URL = BASE_URL + "/pay/queryOrder";
|
||||||
|
|
||||||
|
// ========== 固定支付配置 ==========
|
||||||
|
public static final String ORDER_BODY = "定额测试支付"; // 商品描述
|
||||||
|
public static final int TOTAL_FEE = 1; // 固定金额:1分(沙箱环境推荐)
|
||||||
|
public static final String TRADE_TYPE = "NATIVE"; // 支付类型:二维码
|
||||||
|
|
||||||
|
// ========== 轮询配置 ==========
|
||||||
|
public static final long POLL_INTERVAL = 10000; // 轮询间隔:10秒
|
||||||
|
public static final long POLL_TIMEOUT = 45000; // 轮询超时:45秒
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
package cc.winboll.studio.winboll.activities;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
|
||||||
|
import cc.winboll.studio.winboll.R;
|
||||||
|
import cc.winboll.studio.winboll.WxPayConfig;
|
||||||
|
import cc.winboll.studio.winboll.utils.SpecUtil;
|
||||||
|
import cc.winboll.studio.winboll.utils.WxPayApi;
|
||||||
|
import cc.winboll.studio.winboll.utils.ZXingUtils;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主界面:生成二维码 + 轮询查询支付结果
|
||||||
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
|
* @Date 2026/01/07
|
||||||
|
*/
|
||||||
|
public class WXPayActivity extends WinBoLLActivity implements IWinBoLLActivity {
|
||||||
|
|
||||||
|
private static final String TAG = "WXPayActivity";
|
||||||
|
|
||||||
|
// Handler消息标识
|
||||||
|
private static final int MSG_POLL_TIMEOUT = 1001;
|
||||||
|
private static final int MSG_POLL_SUCCESS = 1002;
|
||||||
|
private static final int MSG_POLL_FAILED = 1003;
|
||||||
|
|
||||||
|
private ImageView mIvQrCode;
|
||||||
|
private TextView mTvOrderNo;
|
||||||
|
private TextView mTvPayStatus;
|
||||||
|
private Button mBtnCreateOrder;
|
||||||
|
|
||||||
|
private String mOutTradeNo; // 商户订单号
|
||||||
|
private Timer mPollTimer; // 轮询定时器
|
||||||
|
private long mPollStartTime; // 轮询开始时间
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Activity getActivity() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Handler mPollHandler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
super.handleMessage(msg);
|
||||||
|
switch (msg.what) {
|
||||||
|
case MSG_POLL_TIMEOUT:
|
||||||
|
stopPoll();
|
||||||
|
mTvPayStatus.setText("支付状态:轮询超时");
|
||||||
|
mTvPayStatus.setTextColor(getResources().getColor(android.R.color.darker_gray));
|
||||||
|
Toast.makeText(WXPayActivity.this, "轮询超时,请手动查询", Toast.LENGTH_SHORT).show();
|
||||||
|
break;
|
||||||
|
case MSG_POLL_SUCCESS:
|
||||||
|
boolean isPaySuccess = (boolean) msg.obj;
|
||||||
|
String tradeState = (String) msg.getData().getString("tradeState");
|
||||||
|
stopPoll();
|
||||||
|
if (isPaySuccess) {
|
||||||
|
mTvPayStatus.setText("支付状态:支付成功 ✅");
|
||||||
|
mTvPayStatus.setTextColor(getResources().getColor(android.R.color.holo_green_dark));
|
||||||
|
Toast.makeText(WXPayActivity.this, "支付成功!", Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
mTvPayStatus.setText("支付状态:" + tradeState);
|
||||||
|
mTvPayStatus.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MSG_POLL_FAILED:
|
||||||
|
String errorMsg = (String) msg.obj;
|
||||||
|
mTvPayStatus.setText("查询失败:" + errorMsg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_wxpay);
|
||||||
|
|
||||||
|
initView();
|
||||||
|
initListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initView() {
|
||||||
|
mIvQrCode = findViewById(R.id.iv_qrcode);
|
||||||
|
mTvOrderNo = findViewById(R.id.tv_order_no);
|
||||||
|
mTvPayStatus = findViewById(R.id.tv_pay_status);
|
||||||
|
mBtnCreateOrder = findViewById(R.id.btn_create_order);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initListener() {
|
||||||
|
mBtnCreateOrder.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
createOrder();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一下单,生成二维码
|
||||||
|
*/
|
||||||
|
private void createOrder() {
|
||||||
|
mBtnCreateOrder.setEnabled(false);
|
||||||
|
mTvPayStatus.setText("支付状态:生成订单中...");
|
||||||
|
mIvQrCode.setImageBitmap(null);
|
||||||
|
|
||||||
|
WxPayApi.createOrder(new WxPayApi.OnCreateOrderCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(String outTradeNo, String codeUrl) {
|
||||||
|
mOutTradeNo = outTradeNo;
|
||||||
|
mTvOrderNo.setText("商户订单号:" + outTradeNo);
|
||||||
|
mTvPayStatus.setText("支付状态:未支付,请扫码");
|
||||||
|
|
||||||
|
// 生成二维码
|
||||||
|
Bitmap qrCodeBitmap = ZXingUtils.createQRCodeBitmap(codeUrl, 250, 250);
|
||||||
|
if (qrCodeBitmap != null) {
|
||||||
|
mIvQrCode.setImageBitmap(qrCodeBitmap);
|
||||||
|
// 开始轮询查询支付结果
|
||||||
|
startPoll();
|
||||||
|
} else {
|
||||||
|
mTvPayStatus.setText("支付状态:生成二维码失败");
|
||||||
|
mBtnCreateOrder.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(String errorMsg) {
|
||||||
|
SpecUtil.WWSpecLogError(TAG, "统一下单失败:" + errorMsg);
|
||||||
|
mTvPayStatus.setText("生成订单失败:" + errorMsg);
|
||||||
|
mBtnCreateOrder.setEnabled(true);
|
||||||
|
Toast.makeText(WXPayActivity.this, errorMsg, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始轮询查询支付结果
|
||||||
|
*/
|
||||||
|
private void startPoll() {
|
||||||
|
stopPoll(); // 先停止之前的轮询
|
||||||
|
mPollStartTime = System.currentTimeMillis();
|
||||||
|
mPollTimer = new Timer();
|
||||||
|
mPollTimer.scheduleAtFixedRate(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// 检查是否超时
|
||||||
|
long elapsedTime = System.currentTimeMillis() - mPollStartTime;
|
||||||
|
if (elapsedTime >= WxPayConfig.POLL_TIMEOUT) {
|
||||||
|
mPollHandler.sendEmptyMessage(MSG_POLL_TIMEOUT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询订单状态
|
||||||
|
WxPayApi.queryOrder(mOutTradeNo, new WxPayApi.OnQueryOrderCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(boolean isPaySuccess, String tradeState) {
|
||||||
|
Message msg = Message.obtain();
|
||||||
|
msg.what = MSG_POLL_SUCCESS;
|
||||||
|
msg.obj = isPaySuccess;
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString("tradeState", tradeState);
|
||||||
|
msg.setData(bundle);
|
||||||
|
mPollHandler.sendMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(String errorMsg) {
|
||||||
|
Message msg = Message.obtain();
|
||||||
|
msg.what = MSG_POLL_FAILED;
|
||||||
|
msg.obj = errorMsg;
|
||||||
|
mPollHandler.sendMessage(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 0, WxPayConfig.POLL_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止轮询
|
||||||
|
*/
|
||||||
|
private void stopPoll() {
|
||||||
|
if (mPollTimer != null) {
|
||||||
|
mPollTimer.cancel();
|
||||||
|
mPollTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
stopPoll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ public class TestWeWorkSpecSDK extends WinBoLLActivity implements IWinBoLLActivi
|
|||||||
|
|
||||||
// ------------------- 企业微信SDK配置常量(需替换为实际项目参数) -------------------
|
// ------------------- 企业微信SDK配置常量(需替换为实际项目参数) -------------------
|
||||||
// 企业微信 CorpID(从企业微信管理后台获取)
|
// 企业微信 CorpID(从企业微信管理后台获取)
|
||||||
private static final String CORP_ID = "your_corp_id_here";
|
private static final String CORP_ID = "wwb37c73f34c722852";
|
||||||
// 应用 AgentID(从企业微信应用管理后台获取)
|
// 应用 AgentID(从企业微信应用管理后台获取)
|
||||||
private static final String AGENT_ID = "your_agent_id_here";
|
private static final String AGENT_ID = "your_agent_id_here";
|
||||||
// 应用 Secret(从企业微信应用管理后台获取,注意保密)
|
// 应用 Secret(从企业微信应用管理后台获取,注意保密)
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package cc.winboll.studio.winboll.utils;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import okhttp3.Call;
|
||||||
|
import okhttp3.Callback;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OkHttp网络请求工具类
|
||||||
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
|
* @Date 2026/01/07
|
||||||
|
*/
|
||||||
|
public class OkHttpUtil {
|
||||||
|
|
||||||
|
private static OkHttpClient sOkHttpClient;
|
||||||
|
private static Handler sMainHandler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
|
static {
|
||||||
|
sOkHttpClient = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET请求
|
||||||
|
* @param url 请求地址
|
||||||
|
* @param callback 回调
|
||||||
|
*/
|
||||||
|
public static void get(String url, final OnResultCallback callback) {
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.get()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
sOkHttpClient.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, final IOException e) {
|
||||||
|
sMainHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call call, final Response response) throws IOException {
|
||||||
|
final String result = response.body().string();
|
||||||
|
sMainHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (callback != null) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
callback.onSuccess(result);
|
||||||
|
} else {
|
||||||
|
callback.onFailure("请求失败:" + response.code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回调接口
|
||||||
|
*/
|
||||||
|
public interface OnResultCallback {
|
||||||
|
void onSuccess(String result);
|
||||||
|
void onFailure(String errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package cc.winboll.studio.winboll.utils;
|
||||||
|
|
||||||
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志工具类(适配项目规范)
|
||||||
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
|
* @Date 2026/01/07
|
||||||
|
*/
|
||||||
|
public class SpecUtil {
|
||||||
|
|
||||||
|
private static final boolean isDebug = true;
|
||||||
|
|
||||||
|
public static void WWSpecLogInfo(String tag, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
LogUtils.i(tag, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WWSpecLogError(String tag, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
LogUtils.e(tag, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package cc.winboll.studio.winboll.utils;
|
||||||
|
|
||||||
|
import cc.winboll.studio.winboll.WxPayConfig;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付服务端接口封装
|
||||||
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
|
* @Date 2026/01/07
|
||||||
|
*/
|
||||||
|
public class WxPayApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一下单(生成二维码)
|
||||||
|
* @param callback 回调
|
||||||
|
*/
|
||||||
|
public static void createOrder(final OnCreateOrderCallback callback) {
|
||||||
|
// 拼接请求参数(服务端测试接口需支持GET传参,若为POST需修改为表单/JSON)
|
||||||
|
String url = WxPayConfig.CREATE_ORDER_URL +
|
||||||
|
"?body=" + WxPayConfig.ORDER_BODY +
|
||||||
|
"&totalFee=" + WxPayConfig.TOTAL_FEE +
|
||||||
|
"&tradeType=" + WxPayConfig.TRADE_TYPE;
|
||||||
|
|
||||||
|
OkHttpUtil.get(url, new OkHttpUtil.OnResultCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(String result) {
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(result);
|
||||||
|
String outTradeNo = jsonObject.getString("out_trade_no");
|
||||||
|
String codeUrl = jsonObject.getString("code_url");
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onSuccess(outTradeNo, codeUrl);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure("解析统一下单结果失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(String errorMsg) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure("统一下单请求失败:" + errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单查询
|
||||||
|
* @param outTradeNo 商户订单号
|
||||||
|
* @param callback 回调
|
||||||
|
*/
|
||||||
|
public static void queryOrder(String outTradeNo, final OnQueryOrderCallback callback) {
|
||||||
|
String url = WxPayConfig.QUERY_ORDER_URL + "?outTradeNo=" + outTradeNo;
|
||||||
|
|
||||||
|
OkHttpUtil.get(url, new OkHttpUtil.OnResultCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(String result) {
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(result);
|
||||||
|
String tradeState = jsonObject.getString("trade_state");
|
||||||
|
boolean isSuccess = "SUCCESS".equals(tradeState);
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onSuccess(isSuccess, tradeState);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure("解析订单查询结果失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(String errorMsg) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure("订单查询请求失败:" + errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一下单回调接口
|
||||||
|
*/
|
||||||
|
public interface OnCreateOrderCallback {
|
||||||
|
void onSuccess(String outTradeNo, String codeUrl);
|
||||||
|
void onFailure(String errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单查询回调接口
|
||||||
|
*/
|
||||||
|
public interface OnQueryOrderCallback {
|
||||||
|
void onSuccess(boolean isPaySuccess, String tradeState);
|
||||||
|
void onFailure(String errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package cc.winboll.studio.winboll.utils;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.EncodeHintType;
|
||||||
|
import com.google.zxing.WriterException;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
import com.google.zxing.qrcode.QRCodeWriter;
|
||||||
|
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||||
|
import com.journeyapps.barcodescanner.BarcodeEncoder;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZXing二维码生成工具类
|
||||||
|
* 依赖:com.google.zxing:core:3.4.1 + com.journeyapps:zxing-android-embedded:3.6.0
|
||||||
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
|
* @Date 2026/01/07
|
||||||
|
*/
|
||||||
|
public class ZXingUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成二维码Bitmap(核心方法,使用journeyapps工具类)
|
||||||
|
* @param content 内容(如微信支付的code_url)
|
||||||
|
* @param width 二维码宽度(px)
|
||||||
|
* @param height 二维码高度(px)
|
||||||
|
* @return 二维码Bitmap,失败返回null
|
||||||
|
*/
|
||||||
|
public static Bitmap createQRCodeBitmap(String content, int width, int height) {
|
||||||
|
// 1. 入参合法性校验
|
||||||
|
if (content == null || content.trim().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 配置二维码参数
|
||||||
|
Map<EncodeHintType, Object> hints = new HashMap<>();
|
||||||
|
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 字符编码
|
||||||
|
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 高容错级别(H级可容忍30%遮挡)
|
||||||
|
hints.put(EncodeHintType.MARGIN, 1); // 边距(值越小,二维码越紧凑,建议1-4)
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 3. 生成BitMatrix(二维码矩阵)
|
||||||
|
QRCodeWriter qrCodeWriter = new QRCodeWriter();
|
||||||
|
BitMatrix bitMatrix = qrCodeWriter.encode(
|
||||||
|
content,
|
||||||
|
BarcodeFormat.QR_CODE,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
hints
|
||||||
|
);
|
||||||
|
|
||||||
|
// 4. 转换BitMatrix为Bitmap(关键:使用journeyapps的BarcodeEncoder)
|
||||||
|
BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
|
||||||
|
return barcodeEncoder.createBitmap(bitMatrix);
|
||||||
|
|
||||||
|
} catch (WriterException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重载方法:生成正方形二维码(宽度=高度)
|
||||||
|
* @param content 内容
|
||||||
|
* @param size 二维码边长(px)
|
||||||
|
* @return 二维码Bitmap
|
||||||
|
*/
|
||||||
|
public static Bitmap createQRCodeBitmap(String content, int size) {
|
||||||
|
return createQRCodeBitmap(content, size, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
43
winboll/src/main/res/layout/activity_wxpay.xml
Normal file
43
winboll/src/main/res/layout/activity_wxpay.xml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?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:orientation="vertical"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="定额支付测试(0.01元)"
|
||||||
|
android:textSize="20sp"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_qrcode"
|
||||||
|
android:layout_width="250dp"
|
||||||
|
android:layout_height="250dp"
|
||||||
|
android:scaleType="fitXY"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_order_no"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="商户订单号:"
|
||||||
|
android:textSize="16sp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_pay_status"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="支付状态:未支付"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@android:color/black"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_create_order"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="生成支付二维码"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -8,6 +8,6 @@
|
|||||||
android:id="@+id/item_settings"
|
android:id="@+id/item_settings"
|
||||||
android:title="Settings"/>
|
android:title="Settings"/>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/item_testweworkspecsdk"
|
android:id="@+id/item_wxpayactivity"
|
||||||
android:title="TestWeWorkSpecSDK"/>
|
android:title="WXPayActivity"/>
|
||||||
</menu>
|
</menu>
|
||||||
|
|||||||
Reference in New Issue
Block a user