├── .gitignore ├── README.md ├── apk └── VirtualXposed_0.9.8.apk ├── app ├── build.gradle ├── libs │ ├── XposedBridgeAPI-89.jar │ ├── core_3.2.0.jar │ ├── jsoup-1.7.2.jar │ ├── myjson-1.5.jar │ ├── nanohttpd-2.3.1-SNAPSHOT.jar │ ├── org.apache.http.legacy.jar │ └── xUtils-2.6.14.jar └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── xposed_init │ ├── java │ └── com │ │ └── tools │ │ └── payhelper │ │ ├── AlarmReceiver.java │ │ ├── AlipayHook.java │ │ ├── CustomApplcation.java │ │ ├── DaemonService.java │ │ ├── HideModule.java │ │ ├── Main.java │ │ ├── MainActivity.java │ │ ├── QQHook.java │ │ ├── QQPlugHook.java │ │ ├── SettingActivity.java │ │ ├── WebServer.java │ │ ├── WechatHook.java │ │ ├── http │ │ ├── CookieJarManager.java │ │ ├── HttpRequest.java │ │ ├── HttpUrl.java │ │ ├── ParamField.java │ │ ├── request │ │ │ └── HttpParams.java │ │ └── result │ │ │ └── BaseResult.java │ │ ├── tcp │ │ ├── TcpCheck.java │ │ ├── TcpConnection.java │ │ ├── TcpSettingActivity.java │ │ └── VerifyData.java │ │ ├── threadpool │ │ ├── ThreadPoolProxy.java │ │ └── ThreadPoolProxyFactory.java │ │ └── utils │ │ ├── AbSharedUtil.java │ │ ├── BitmapUtil.java │ │ ├── CrashHandler.java │ │ ├── DBHelper.java │ │ ├── DBManager.java │ │ ├── ExecutorManager.java │ │ ├── ImageUtils.java │ │ ├── JsonHelper.java │ │ ├── LauncherLimitUtils.java │ │ ├── LogToFile.java │ │ ├── LogUtils.java │ │ ├── Logger.java │ │ ├── MD5.java │ │ ├── OrderBean.java │ │ ├── PayHelperUtils.java │ │ ├── QQDBHelper.java │ │ ├── QQDBManager.java │ │ ├── QRUtils.java │ │ ├── QrCodeBean.java │ │ ├── StringUtils.java │ │ ├── Tag.java │ │ ├── TimeUtils.java │ │ └── XmlToJson.java │ └── res │ ├── drawable-hdpi │ ├── btn_back_grey.png │ └── ic_launcher.png │ ├── drawable-ldpi │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ └── ic_launcher.png │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── drawable │ └── button.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_setting.xml │ └── activity_tcp_setting.xml │ ├── menu │ └── main.xml │ ├── values-sw600dp │ └── dimens.xml │ ├── values-sw720dp-land │ └── dimens.xml │ ├── values-v11 │ └── styles.xml │ ├── values-v14 │ └── styles.xml │ └── values │ ├── dimens.xml │ ├── jpush_style.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── import-summary.txt ├── keystore └── key.key ├── local.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PayHelper6.6.7_NewAPI 2 | The demo of Xposed. 3 | -------------------------------------------------------------------------------- /apk/VirtualXposed_0.9.8.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/apk/VirtualXposed_0.9.8.apk -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | static def buildTime() { 4 | return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) 5 | } 6 | 7 | android { 8 | compileSdkVersion 25 9 | 10 | defaultConfig { 11 | applicationId "com.tools.payhelper1" 12 | minSdkVersion 15 13 | targetSdkVersion 28 14 | versionCode 2 15 | versionName "2.0.0" 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 17 | buildConfigField "String", "BUILD_TIME", "\"${buildTime()}\"" 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | } 30 | 31 | dependencies { 32 | // implementation 'com.android.support:appcompat-v7:28.0.0' 33 | implementation 'com.android.support:support-v4:25.3.1' 34 | implementation files('libs/XposedBridgeAPI-89.jar') 35 | implementation files('libs/core_3.2.0.jar') 36 | implementation files('libs/jsoup-1.7.2.jar') 37 | implementation files('libs/myjson-1.5.jar') 38 | implementation files('libs/nanohttpd-2.3.1-SNAPSHOT.jar') 39 | implementation files('libs/org.apache.http.legacy.jar') 40 | implementation files('libs/xUtils-2.6.14.jar') 41 | 42 | 43 | implementation rootProject.ext.lib_okhttp_okhttp 44 | implementation rootProject.ext.lib_okhttp_okio 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/libs/XposedBridgeAPI-89.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/libs/XposedBridgeAPI-89.jar -------------------------------------------------------------------------------- /app/libs/core_3.2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/libs/core_3.2.0.jar -------------------------------------------------------------------------------- /app/libs/jsoup-1.7.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/libs/jsoup-1.7.2.jar -------------------------------------------------------------------------------- /app/libs/myjson-1.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/libs/myjson-1.5.jar -------------------------------------------------------------------------------- /app/libs/nanohttpd-2.3.1-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/libs/nanohttpd-2.3.1-SNAPSHOT.jar -------------------------------------------------------------------------------- /app/libs/org.apache.http.legacy.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/libs/org.apache.http.legacy.jar -------------------------------------------------------------------------------- /app/libs/xUtils-2.6.14.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/libs/xUtils-2.6.14.jar -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 40 | 45 | 46 | 51 | 52 | 55 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | com.tools.payhelper.Main -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/AlarmReceiver.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | import java.util.List; 4 | 5 | import com.tools.payhelper.utils.DBManager; 6 | import com.tools.payhelper.utils.OrderBean; 7 | import com.tools.payhelper.utils.PayHelperUtils; 8 | 9 | import android.content.BroadcastReceiver; 10 | import android.content.Context; 11 | import android.content.Intent; 12 | 13 | /** 14 | * 15 | 16 | * @ClassName: AlarmReceiver 17 | 18 | * @Description: TODO(这里用一句话描述这个类的作用) 19 | 20 | * @author SuXiaoliang 21 | 22 | * @date 2018年6月23日 下午1:25:47 23 | 24 | * 25 | */ 26 | 27 | public class AlarmReceiver extends BroadcastReceiver{ 28 | 29 | @Override 30 | public void onReceive(Context context, Intent intent) { 31 | try { 32 | DBManager dbManager=new DBManager(context); 33 | List orderBeans=dbManager.FindAllOrders(); 34 | for (OrderBean orderBean : orderBeans) { 35 | PayHelperUtils.notify(context, orderBean.getType(), orderBean.getNo(), orderBean.getMoney(), orderBean.getMark(), orderBean.getDt()); 36 | } 37 | long currentTimeMillis=System.currentTimeMillis()/1000; 38 | long currentTimeMillis2=Long.parseLong(PayHelperUtils.getcurrentTimeMillis(context)); 39 | long currentTimeMillis3=currentTimeMillis-currentTimeMillis2; 40 | if(currentTimeMillis3>120 && currentTimeMillis2!=0){ 41 | PayHelperUtils.sendmsg(context, "轮询任务出现异常,重启中..."); 42 | PayHelperUtils.startAlipayMonitor(context); 43 | PayHelperUtils.sendmsg(context, "轮询任务重启成功"); 44 | } 45 | } catch (Exception e) { 46 | PayHelperUtils.sendmsg(context, "AlarmReceiver异常->>"+e.getMessage()); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/AlipayHook.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | 4 | 5 | import java.lang.reflect.Field; 6 | import java.util.Map; 7 | 8 | import org.json.JSONObject; 9 | 10 | import com.tools.payhelper.utils.LogToFile; 11 | import com.tools.payhelper.utils.PayHelperUtils; 12 | import com.tools.payhelper.utils.StringUtils; 13 | 14 | import android.app.Activity; 15 | import android.content.Context; 16 | import android.content.Intent; 17 | import android.os.Bundle; 18 | import android.widget.Button; 19 | import de.robv.android.xposed.XC_MethodHook; 20 | import de.robv.android.xposed.XC_MethodReplacement; 21 | import de.robv.android.xposed.XposedBridge; 22 | import de.robv.android.xposed.XposedHelpers; 23 | 24 | /** 25 | * 26 | 27 | * @ClassName: AlipayHook 28 | 29 | * @Description: TODO(这里用一句话描述这个类的作用) 30 | 31 | * @author SuXiaoliang 32 | 33 | * @date 2018年6月23日 下午1:25:54 34 | 35 | * 36 | */ 37 | 38 | public class AlipayHook { 39 | 40 | public static String BILLRECEIVED_ACTION = "com.tools.payhelper.billreceived"; 41 | public static String QRCODERECEIVED_ACTION = "com.tools.payhelper.qrcodereceived"; 42 | public static String SAVEALIPAYCOOKIE_ACTION = "com.tools.payhelper.savealipaycookie"; 43 | 44 | public void hook(final ClassLoader classLoader,final Context context) { 45 | securityCheckHook(classLoader); 46 | try { 47 | Class insertTradeMessageInfo = XposedHelpers.findClass("com.alipay.android.phone.messageboxstatic.biz.dao.TradeDao", classLoader); 48 | XposedBridge.hookAllMethods(insertTradeMessageInfo, "insertMessageInfo", new XC_MethodHook() { 49 | @Override 50 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 51 | try { 52 | XposedBridge.log("======支付宝个人账号订单start========="); 53 | 54 | //更新cookie 55 | Intent cookieBroadCastIntent = new Intent(); 56 | String alipaycookie=PayHelperUtils.getCookieStr(classLoader); 57 | cookieBroadCastIntent.putExtra("alipaycookie", alipaycookie); 58 | cookieBroadCastIntent.setAction(SAVEALIPAYCOOKIE_ACTION); 59 | context.sendBroadcast(cookieBroadCastIntent); 60 | 61 | //获取content字段 62 | // String content=(String) XposedHelpers.getObjectField(param.args[0], "content"); 63 | // XposedBridge.log(content); 64 | //获取全部字段 65 | Object object = param.args[0]; 66 | String MessageInfo = (String) XposedHelpers.callMethod(object, "toString"); 67 | XposedBridge.log(MessageInfo); 68 | String content=StringUtils.getTextCenter(MessageInfo, "content='", "'"); 69 | if(content.contains("二维码收款") || content.contains("收到一笔转账")){ 70 | JSONObject jsonObject=new JSONObject(content); 71 | String money=jsonObject.getString("content").replace("¥", ""); 72 | String mark=jsonObject.getString("assistMsg2"); 73 | String tradeNo=StringUtils.getTextCenter(MessageInfo,"tradeNO=","&"); 74 | XposedBridge.log("收到支付宝支付订单:"+tradeNo+"=="+money+"=="+mark); 75 | 76 | Intent broadCastIntent = new Intent(); 77 | broadCastIntent.putExtra("bill_no", tradeNo); 78 | broadCastIntent.putExtra("bill_money", money); 79 | broadCastIntent.putExtra("bill_mark", mark); 80 | broadCastIntent.putExtra("bill_type", "alipay"); 81 | broadCastIntent.setAction(BILLRECEIVED_ACTION); 82 | context.sendBroadcast(broadCastIntent); 83 | } 84 | XposedBridge.log("======支付宝个人账号订单end========="); 85 | } catch (Exception e) { 86 | XposedBridge.log(e.getMessage()); 87 | } 88 | super.beforeHookedMethod(param); 89 | } 90 | }); 91 | Class insertServiceMessageInfo = XposedHelpers.findClass("com.alipay.android.phone.messageboxstatic.biz.dao.ServiceDao", classLoader); 92 | XposedBridge.hookAllMethods(insertServiceMessageInfo, "insertMessageInfo", new XC_MethodHook() { 93 | @Override 94 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 95 | try { 96 | XposedBridge.log("======支付宝商家服务订单start========="); 97 | 98 | //更新cookie 99 | Intent cookieBroadCastIntent = new Intent(); 100 | String alipaycookie=PayHelperUtils.getCookieStr(classLoader); 101 | cookieBroadCastIntent.putExtra("alipaycookie", alipaycookie); 102 | cookieBroadCastIntent.setAction(SAVEALIPAYCOOKIE_ACTION); 103 | context.sendBroadcast(cookieBroadCastIntent); 104 | 105 | Object object = param.args[0]; 106 | String MessageInfo = (String) XposedHelpers.callMethod(object, "toString"); 107 | String content=StringUtils.getTextCenter(MessageInfo, "extraInfo='", "'").replace("\\", ""); 108 | XposedBridge.log(content); 109 | if(content.contains("店员通")){ 110 | String money=StringUtils.getTextCenter(content, "mainAmount\":\"", "\",\"mainTitle"); 111 | String time=StringUtils.getTextCenter(content, "gmtCreate\":", ",gmtValid"); 112 | String no=PayHelperUtils.getOrderId(); 113 | Intent broadCastIntent = new Intent(); 114 | broadCastIntent.putExtra("bill_no", no); 115 | broadCastIntent.putExtra("bill_money", money); 116 | broadCastIntent.putExtra("bill_mark", ""); 117 | broadCastIntent.putExtra("bill_time", time); 118 | broadCastIntent.putExtra("bill_type", "alipay_dy"); 119 | broadCastIntent.setAction(BILLRECEIVED_ACTION); 120 | context.sendBroadcast(broadCastIntent); 121 | }else if(content.contains("收钱到账") || content.contains("收款到账")){ 122 | LogToFile.i("payhelper", "Hook到商家服务通知,开始调用getBill获取订单详细信息"); 123 | String userId=PayHelperUtils.getAlipayUserId(classLoader); 124 | PayHelperUtils.getBill(context,alipaycookie,userId); 125 | } 126 | XposedBridge.log("======支付宝商家服务订单end========="); 127 | } catch (Exception e) { 128 | PayHelperUtils.sendmsg(context, e.getMessage()); 129 | } 130 | super.beforeHookedMethod(param); 131 | } 132 | }); 133 | 134 | // hook设置金额和备注的onCreate方法,自动填写数据并点击 135 | XposedHelpers.findAndHookMethod("com.alipay.mobile.payee.ui.PayeeQRSetMoneyActivity", classLoader, "onCreate", Bundle.class, new XC_MethodHook() { 136 | @Override 137 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 138 | XposedBridge.log("========支付宝设置金额start========="); 139 | 140 | //更新cookie 141 | Intent cookieBroadCastIntent = new Intent(); 142 | String alipaycookie=PayHelperUtils.getCookieStr(classLoader); 143 | cookieBroadCastIntent.putExtra("alipaycookie", alipaycookie); 144 | cookieBroadCastIntent.setAction(SAVEALIPAYCOOKIE_ACTION); 145 | context.sendBroadcast(cookieBroadCastIntent); 146 | 147 | Field jinErField = XposedHelpers.findField(param.thisObject.getClass(), "b"); 148 | final Object jinErView = jinErField.get(param.thisObject); 149 | Field beiZhuField = XposedHelpers.findField(param.thisObject.getClass(), "c"); 150 | final Object beiZhuView = beiZhuField.get(param.thisObject); 151 | Intent intent = ((Activity) param.thisObject).getIntent(); 152 | String mark=intent.getStringExtra("mark"); 153 | String money=intent.getStringExtra("money"); 154 | //设置支付宝金额和备注 155 | XposedHelpers.callMethod(jinErView, "setText", money); 156 | XposedHelpers.callMethod(beiZhuView, "setText", mark); 157 | //点击确认 158 | Field quRenField = XposedHelpers.findField(param.thisObject.getClass(), "e"); 159 | final Button quRenButton = (Button) quRenField.get(param.thisObject); 160 | quRenButton.performClick(); 161 | XposedBridge.log("=========支付宝设置金额end========"); 162 | } 163 | }); 164 | 165 | // hook获得二维码url的回调方法 166 | XposedHelpers.findAndHookMethod("com.alipay.mobile.payee.ui.PayeeQRSetMoneyActivity", classLoader, "a", 167 | XposedHelpers.findClass("com.alipay.transferprod.rpc.result.ConsultSetAmountRes", classLoader), new XC_MethodHook() { 168 | @Override 169 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 170 | XposedBridge.log("=========支付宝生成完成start========"); 171 | Field moneyField = XposedHelpers.findField(param.thisObject.getClass(), "g"); 172 | String money = (String) moneyField.get(param.thisObject); 173 | 174 | Field markField = XposedHelpers.findField(param.thisObject.getClass(), "c"); 175 | Object markObject = markField.get(param.thisObject); 176 | String mark=(String) XposedHelpers.callMethod(markObject, "getUbbStr"); 177 | 178 | Object consultSetAmountRes = param.args[0]; 179 | Field consultField = XposedHelpers.findField(consultSetAmountRes.getClass(), "qrCodeUrl"); 180 | String payurl = (String) consultField.get(consultSetAmountRes); 181 | XposedBridge.log(money+" "+mark+" "+payurl); 182 | 183 | if(money!=null){ 184 | XposedBridge.log("调用增加数据方法==>支付宝"); 185 | Intent broadCastIntent = new Intent(); 186 | broadCastIntent.putExtra("money", money); 187 | broadCastIntent.putExtra("mark", mark); 188 | broadCastIntent.putExtra("type", "alipay"); 189 | broadCastIntent.putExtra("payurl", payurl); 190 | broadCastIntent.setAction(QRCODERECEIVED_ACTION); 191 | context.sendBroadcast(broadCastIntent); 192 | } 193 | XposedBridge.log("=========支付宝生成完成end========"); 194 | } 195 | }); 196 | 197 | // hook获取loginid 198 | XposedHelpers.findAndHookMethod("com.alipay.mobile.quinox.LauncherActivity", classLoader, "onResume", 199 | new XC_MethodHook() { 200 | @Override 201 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 202 | PayHelperUtils.isFirst=true; 203 | String loginid=PayHelperUtils.getAlipayLoginId(classLoader); 204 | PayHelperUtils.sendLoginId(loginid, "alipay", context); 205 | } 206 | }); 207 | 208 | //拦截“人气大爆发,一会再试试” 209 | XposedHelpers.findAndHookMethod("com.alipay.mobile.antui.basic.AUDialog", classLoader, "show", 210 | new XC_MethodHook() { 211 | 212 | @Override 213 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 214 | Context mContext=(Context) XposedHelpers.getObjectField(param.thisObject, "mContext"); 215 | if (mContext.getClass().getSimpleName().equals("PayeeQRSetMoneyActivity")){ 216 | XposedHelpers.setObjectField(param.thisObject, "mContext", null); 217 | } 218 | } 219 | 220 | }); 221 | 222 | //拦截设置cookie 223 | XposedHelpers.findAndHookMethod("com.alipay.mobile.common.transport.http.GwCookieCacheHelper", classLoader, "setCookies",String.class,Map.class, 224 | new XC_MethodHook() { 225 | 226 | @Override 227 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 228 | String domain=param.args[0].toString(); 229 | Map cookie=(Map)param.args[1]; 230 | String ck=(String) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.alipay.mobile.common.transport.http.GwCookieCacheHelper", classLoader), "toCookieString",cookie); 231 | if(ck.contains("ALIPAYJSESSIONID")){ 232 | //更新cookie 233 | Intent cookieBroadCastIntent = new Intent(); 234 | cookieBroadCastIntent.putExtra("alipaycookie", ck); 235 | cookieBroadCastIntent.setAction(SAVEALIPAYCOOKIE_ACTION); 236 | context.sendBroadcast(cookieBroadCastIntent); 237 | } 238 | } 239 | 240 | }); 241 | } catch (Error | Exception e) { 242 | PayHelperUtils.sendmsg(context, e.getMessage()); 243 | } 244 | } 245 | 246 | private void securityCheckHook(ClassLoader classLoader) { 247 | try { 248 | Class securityCheckClazz = XposedHelpers.findClass("com.alipay.mobile.base.security.CI", classLoader); 249 | XposedHelpers.findAndHookMethod(securityCheckClazz, "a", String.class, String.class, String.class, new XC_MethodHook() { 250 | @Override 251 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 252 | Object object = param.getResult(); 253 | XposedHelpers.setBooleanField(object, "a", false); 254 | param.setResult(object); 255 | super.afterHookedMethod(param); 256 | } 257 | }); 258 | 259 | XposedHelpers.findAndHookMethod(securityCheckClazz, "a", Class.class, String.class, String.class, new XC_MethodReplacement() { 260 | @Override 261 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 262 | return (byte) 1; 263 | } 264 | }); 265 | XposedHelpers.findAndHookMethod(securityCheckClazz, "a", ClassLoader.class, String.class, new XC_MethodReplacement() { 266 | @Override 267 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 268 | return (byte) 1; 269 | } 270 | }); 271 | XposedHelpers.findAndHookMethod(securityCheckClazz, "a", new XC_MethodReplacement() { 272 | @Override 273 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 274 | return false; 275 | } 276 | }); 277 | 278 | } catch (Error | Exception e) { 279 | e.printStackTrace(); 280 | } 281 | } 282 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/CustomApplcation.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | 4 | import com.tools.payhelper.utils.CrashHandler; 5 | import com.tools.payhelper.utils.LogUtils; 6 | 7 | import android.app.Application; 8 | import android.content.Context; 9 | 10 | /** 11 | * @author SuXiaoliang 12 | * @ClassName: CustomApplcation 13 | * @Description: TODO(这里用一句话描述这个类的作用) 14 | * @date 2018年6月23日 下午1:26:02 15 | */ 16 | 17 | public class CustomApplcation extends Application { 18 | 19 | public static CustomApplcation mInstance; 20 | private static Context context; 21 | 22 | @Override 23 | public void onCreate() { 24 | super.onCreate(); 25 | // 崩溃记录 26 | context = getApplicationContext(); 27 | CrashHandler crashHandler = CrashHandler.getInstance(); 28 | crashHandler.init(context); 29 | LogUtils.init(context, true, false); 30 | mInstance = this; 31 | } 32 | 33 | public static CustomApplcation getInstance() { 34 | return mInstance; 35 | } 36 | 37 | public static Context getContext() { 38 | return context; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/DaemonService.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | import com.tools.payhelper.utils.AbSharedUtil; 4 | import com.tools.payhelper.utils.PayHelperUtils; 5 | 6 | import android.app.AlarmManager; 7 | import android.app.Notification; 8 | import android.app.NotificationManager; 9 | import android.app.PendingIntent; 10 | import android.app.Service; 11 | import android.content.Intent; 12 | import android.content.IntentFilter; 13 | import android.os.Build; 14 | import android.os.IBinder; 15 | import android.os.SystemClock; 16 | import android.support.annotation.Nullable; 17 | import de.robv.android.xposed.XposedBridge; 18 | 19 | /** 20 | * 21 | 22 | * @ClassName: DaemonService 23 | 24 | * @Description: TODO(这里用一句话描述这个类的作用) 25 | 26 | * @author SuXiaoliang 27 | 28 | * @date 2018年6月23日 下午1:26:14 29 | 30 | * 31 | */ 32 | public class DaemonService extends Service { 33 | public static String NOTIFY_ACTION = "com.tools.payhelper.notify"; 34 | private static final String TAG = "DaemonService"; 35 | public static final int NOTICE_ID = 100; 36 | 37 | @Nullable 38 | @Override 39 | public IBinder onBind(Intent intent) { 40 | return null; 41 | } 42 | 43 | 44 | @Override 45 | public void onCreate() { 46 | super.onCreate(); 47 | //如果API大于18,需要弹出一个可见通知 48 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){ 49 | Notification.Builder builder = new Notification.Builder(this); 50 | builder.setSmallIcon(R.drawable.ic_launcher); 51 | builder.setContentTitle("收款助手"); 52 | builder.setContentText("收款助手正在运行中..."); 53 | builder.setAutoCancel(false); 54 | builder.setOngoing(true); 55 | startForeground(NOTICE_ID,builder.build()); 56 | }else{ 57 | startForeground(NOTICE_ID,new Notification()); 58 | } 59 | PayHelperUtils.sendmsg(getApplicationContext(), "启动定时任务"); 60 | 61 | AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); 62 | int time=AbSharedUtil.getInt(getApplicationContext(), "time"); 63 | int triggerTime = 3 * 60 * 1000; 64 | if(time!=0){ 65 | triggerTime = time * 1000; 66 | } 67 | Intent i = new Intent(NOTIFY_ACTION); 68 | PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT); 69 | manager.setRepeating(AlarmManager.RTC_WAKEUP , System.currentTimeMillis(), triggerTime, pi); 70 | 71 | } 72 | 73 | @Override 74 | public int onStartCommand(Intent intent, int flags, int startId) { 75 | // 如果Service被终止 76 | // 当资源允许情况下,重启service 77 | return START_STICKY; 78 | } 79 | 80 | 81 | @Override 82 | public void onDestroy() { 83 | super.onDestroy(); 84 | // 如果Service被杀死,干掉通知 85 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){ 86 | NotificationManager mManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); 87 | mManager.cancel(NOTICE_ID); 88 | } 89 | // 重启自己 90 | Intent intent = new Intent(getApplicationContext(),DaemonService.class); 91 | startService(intent); 92 | } 93 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/HideModule.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | import android.app.ActivityManager; 4 | import android.content.pm.ApplicationInfo; 5 | import android.content.pm.PackageInfo; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import de.robv.android.xposed.XC_MethodHook; 11 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 12 | 13 | import static de.robv.android.xposed.XposedBridge.log; 14 | import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; 15 | 16 | /** 17 | * 18 | 19 | * @ClassName: HideModule 20 | 21 | * @Description: TODO(这里用一句话描述这个类的作用) 22 | 23 | * @author SuXiaoliang 24 | 25 | * @date 2018年6月23日 下午1:26:20 26 | 27 | * 28 | */ 29 | public class HideModule { 30 | 31 | static void hideModule(XC_LoadPackage.LoadPackageParam loadPackageParam) { 32 | findAndHookMethod("android.app.ApplicationPackageManager", loadPackageParam.classLoader, "getInstalledApplications", int.class, new XC_MethodHook() { 33 | @Override 34 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 35 | List applicationList = (List) param.getResult(); 36 | List resultapplicationList = new ArrayList<>(); 37 | for (ApplicationInfo applicationInfo : applicationList) { 38 | String packageName = applicationInfo.packageName; 39 | if (isTarget(packageName)) { 40 | log("Hid package: " + packageName); 41 | } else { 42 | resultapplicationList.add(applicationInfo); 43 | } 44 | } 45 | param.setResult(resultapplicationList); 46 | } 47 | }); 48 | findAndHookMethod("android.app.ApplicationPackageManager", loadPackageParam.classLoader, "getInstalledPackages", int.class, new XC_MethodHook() { 49 | @Override 50 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 51 | List packageInfoList = (List) param.getResult(); 52 | List resultpackageInfoList = new ArrayList<>(); 53 | 54 | for (PackageInfo packageInfo : packageInfoList) { 55 | String packageName = packageInfo.packageName; 56 | if (isTarget(packageName)) { 57 | log("Hid package: " + packageName); 58 | } else { 59 | resultpackageInfoList.add(packageInfo); 60 | } 61 | } 62 | param.setResult(resultpackageInfoList); 63 | } 64 | }); 65 | findAndHookMethod("android.app.ApplicationPackageManager", loadPackageParam.classLoader, "getPackageInfo", String.class, int.class, new XC_MethodHook() { 66 | @Override 67 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 68 | String packageName = (String) param.args[0]; 69 | if (isTarget(packageName)) { 70 | param.args[0] = Main.QQ_PACKAGE; 71 | log("Fake package: " + packageName + " as " + Main.QQ_PACKAGE); 72 | } 73 | } 74 | }); 75 | findAndHookMethod("android.app.ApplicationPackageManager", loadPackageParam.classLoader, "getApplicationInfo", String.class, int.class, new XC_MethodHook() { 76 | @Override 77 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 78 | String packageName = (String) param.args[0]; 79 | if (isTarget(packageName)) { 80 | param.args[0] = Main.QQ_PACKAGE; 81 | log("Fake package: " + packageName + " as " + Main.QQ_PACKAGE); 82 | } 83 | } 84 | }); 85 | findAndHookMethod("android.app.ActivityManager", loadPackageParam.classLoader, "getRunningServices", int.class, new XC_MethodHook() { 86 | @Override 87 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 88 | List serviceInfoList = (List) param.getResult(); 89 | List resultList = new ArrayList<>(); 90 | 91 | for (ActivityManager.RunningServiceInfo runningServiceInfo : serviceInfoList) { 92 | String serviceName = runningServiceInfo.process; 93 | if (isTarget(serviceName)) { 94 | log("Hid service: " + serviceName); 95 | } else { 96 | resultList.add(runningServiceInfo); 97 | } 98 | } 99 | param.setResult(resultList); 100 | } 101 | }); 102 | findAndHookMethod("android.app.ActivityManager", loadPackageParam.classLoader, "getRunningTasks", int.class, new XC_MethodHook() { 103 | @Override 104 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 105 | List serviceInfoList = (List) param.getResult(); 106 | List resultList = new ArrayList<>(); 107 | 108 | for (ActivityManager.RunningTaskInfo runningTaskInfo : serviceInfoList) { 109 | String taskName = runningTaskInfo.baseActivity.flattenToString(); 110 | if (isTarget(taskName)) { 111 | log("Hid task: " + taskName); 112 | } else { 113 | resultList.add(runningTaskInfo); 114 | } 115 | } 116 | param.setResult(resultList); 117 | } 118 | }); 119 | findAndHookMethod("android.app.ActivityManager", loadPackageParam.classLoader, "getRunningAppProcesses", new XC_MethodHook() { 120 | @Override 121 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 122 | List runningAppProcessInfos = (List) param.getResult(); 123 | List resultList = new ArrayList<>(); 124 | 125 | for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcessInfos) { 126 | String processName = runningAppProcessInfo.processName; 127 | if (isTarget(processName)) { 128 | log("Hid process: " + processName); 129 | } else { 130 | resultList.add(runningAppProcessInfo); 131 | } 132 | } 133 | param.setResult(resultList); 134 | } 135 | }); 136 | } 137 | 138 | private static boolean isTarget(String name) { 139 | return name.contains("payhelper") || name.contains("xposed"); 140 | } 141 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/Main.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | import java.io.File; 4 | 5 | import com.tools.payhelper.utils.PayHelperUtils; 6 | import com.tools.payhelper.utils.QQDBManager; 7 | 8 | import android.app.Application; 9 | import android.content.BroadcastReceiver; 10 | import android.content.Context; 11 | import android.content.ContextWrapper; 12 | import android.content.Intent; 13 | import android.content.IntentFilter; 14 | import android.content.pm.ApplicationInfo; 15 | import android.net.Uri; 16 | import android.text.TextUtils; 17 | import dalvik.system.BaseDexClassLoader; 18 | import de.robv.android.xposed.IXposedHookLoadPackage; 19 | import de.robv.android.xposed.XC_MethodHook; 20 | import de.robv.android.xposed.XposedBridge; 21 | import de.robv.android.xposed.XposedHelpers; 22 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 23 | 24 | /** 25 | * 26 | 27 | * @ClassName: Main 28 | 29 | * @Description: TODO(这里用一句话描述这个类的作用) 30 | 31 | * @author SuXiaoliang 32 | 33 | * @date 2018年6月23日 下午1:26:26 34 | 35 | * 36 | */ 37 | public class Main implements IXposedHookLoadPackage { 38 | public static String WECHAT_PACKAGE = "com.tencent.mm"; 39 | public static String ALIPAY_PACKAGE = "com.eg.android.AlipayGphone"; 40 | public static String QQ_PACKAGE = "com.tencent.mobileqq"; 41 | public static String QQ_WALLET_PACKAGE = "com.qwallet"; 42 | public static boolean WECHAT_PACKAGE_ISHOOK = false; 43 | public static boolean ALIPAY_PACKAGE_ISHOOK = false; 44 | public static boolean QQ_PACKAGE_ISHOOK = false; 45 | public static boolean QQ_WALLET_ISHOOK = false; 46 | 47 | 48 | @Override 49 | public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) 50 | throws Throwable { 51 | if (lpparam.appInfo == null || (lpparam.appInfo.flags & (ApplicationInfo.FLAG_SYSTEM | 52 | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) { 53 | return; 54 | } 55 | final String packageName = lpparam.packageName; 56 | final String processName = lpparam.processName; 57 | if (WECHAT_PACKAGE.equals(packageName)) { 58 | try { 59 | XposedHelpers.findAndHookMethod(ContextWrapper.class, "attachBaseContext", Context.class, new XC_MethodHook() { 60 | @Override 61 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { 62 | super.afterHookedMethod(param); 63 | Context context = (Context) param.args[0]; 64 | ClassLoader appClassLoader = context.getClassLoader(); 65 | if(WECHAT_PACKAGE.equals(processName) && !WECHAT_PACKAGE_ISHOOK){ 66 | WECHAT_PACKAGE_ISHOOK=true; 67 | //注册广播 68 | StartWechatReceived stratWechat=new StartWechatReceived(); 69 | IntentFilter intentFilter = new IntentFilter(); 70 | intentFilter.addAction("com.payhelper.wechat.start"); 71 | context.registerReceiver(stratWechat, intentFilter); 72 | XposedBridge.log("handleLoadPackage: " + packageName); 73 | PayHelperUtils.sendmsg(context, "微信Hook成功,当前微信版本:"+PayHelperUtils.getVerName(context)); 74 | new WechatHook().hook(appClassLoader,context); 75 | } 76 | } 77 | }); 78 | } catch (Throwable e) { 79 | XposedBridge.log(e); 80 | } 81 | }else if(ALIPAY_PACKAGE.equals(packageName)){ 82 | try { 83 | XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() { 84 | @Override 85 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { 86 | super.afterHookedMethod(param); 87 | Context context = (Context) param.args[0]; 88 | ClassLoader appClassLoader = context.getClassLoader(); 89 | if(ALIPAY_PACKAGE.equals(processName) && !ALIPAY_PACKAGE_ISHOOK){ 90 | ALIPAY_PACKAGE_ISHOOK=true; 91 | //注册广播 92 | StartAlipayReceived startAlipay=new StartAlipayReceived(); 93 | IntentFilter intentFilter = new IntentFilter(); 94 | intentFilter.addAction("com.payhelper.alipay.start"); 95 | context.registerReceiver(startAlipay, intentFilter); 96 | XposedBridge.log("handleLoadPackage: " + packageName); 97 | PayHelperUtils.sendmsg(context, "支付宝Hook成功,当前支付宝版本:"+PayHelperUtils.getVerName(context)); 98 | new AlipayHook().hook(appClassLoader,context); 99 | } 100 | } 101 | }); 102 | }catch (Throwable e) { 103 | XposedBridge.log(e); 104 | } 105 | }else if(QQ_PACKAGE.equals(packageName)){ 106 | try { 107 | XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() { 108 | @Override 109 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { 110 | super.afterHookedMethod(param); 111 | Context context = (Context) param.args[0]; 112 | ClassLoader appClassLoader = context.getClassLoader(); 113 | if(QQ_PACKAGE.equals(processName) && !QQ_PACKAGE_ISHOOK){ 114 | QQ_PACKAGE_ISHOOK=true; 115 | //注册广播 116 | StartQQReceived startQQ=new StartQQReceived(); 117 | IntentFilter intentFilter = new IntentFilter(); 118 | intentFilter.addAction("com.payhelper.qq.start"); 119 | context.registerReceiver(startQQ, intentFilter); 120 | XposedBridge.log("handleLoadPackage: " + packageName); 121 | PayHelperUtils.sendmsg(context, "QQHook成功,当前QQ版本:"+PayHelperUtils.getVerName(context)); 122 | new QQHook().hook(appClassLoader,context); 123 | } 124 | } 125 | }); 126 | 127 | XposedHelpers.findAndHookConstructor("dalvik.system.BaseDexClassLoader", 128 | lpparam.classLoader, String.class, File.class, String.class, ClassLoader.class, new XC_MethodHook() { 129 | @Override 130 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { 131 | 132 | if (param.args[0].toString().contains("qwallet_plugin.apk")) { 133 | ClassLoader classLoader = (BaseDexClassLoader) param.thisObject; 134 | new QQPlugHook().hook(classLoader); 135 | } 136 | } 137 | }); 138 | }catch (Exception e) { 139 | XposedBridge.log(e); 140 | } 141 | } 142 | } 143 | 144 | 145 | //自定义启动微信广播 146 | class StartWechatReceived extends BroadcastReceiver { 147 | @Override 148 | public void onReceive(Context context, Intent intent) { 149 | XposedBridge.log("启动微信Activity"); 150 | try { 151 | Intent intent2=new Intent(context, XposedHelpers.findClass("com.tencent.mm.plugin.collect.ui.CollectCreateQRCodeUI", context.getClassLoader())); 152 | intent2.putExtra("mark", intent.getStringExtra("mark")); 153 | intent2.putExtra("money", intent.getStringExtra("money")); 154 | intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 155 | context.startActivity(intent2); 156 | XposedBridge.log("启动微信成功"); 157 | } catch (Exception e) { 158 | XposedBridge.log("启动微信失败:"+e.getMessage()); 159 | } 160 | } 161 | } 162 | //自定义启动支付宝广播 163 | class StartAlipayReceived extends BroadcastReceiver { 164 | @Override 165 | public void onReceive(Context context, Intent intent) { 166 | XposedBridge.log("启动支付宝Activity"); 167 | Intent intent2=new Intent(context, XposedHelpers.findClass("com.alipay.mobile.payee.ui.PayeeQRSetMoneyActivity", context.getClassLoader())); 168 | intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 169 | intent2.putExtra("mark", intent.getStringExtra("mark")); 170 | intent2.putExtra("money", intent.getStringExtra("money")); 171 | context.startActivity(intent2); 172 | } 173 | } 174 | 175 | //自定义启动QQ广播 176 | class StartQQReceived extends BroadcastReceiver { 177 | @Override 178 | public void onReceive(Context context, Intent intent) { 179 | XposedBridge.log("启动QQActivity"); 180 | try { 181 | // PayHelperUtils.sendmsg(context, "启动QQActivity"+l); 182 | 183 | String money=intent.getStringExtra("money"); 184 | String mark=intent.getStringExtra("mark"); 185 | if(!TextUtils.isEmpty(money) && !TextUtils.isEmpty(mark)){ 186 | QQDBManager qqdbManager=new QQDBManager(context); 187 | qqdbManager.addQQMark(intent.getStringExtra("money"),intent.getStringExtra("mark")); 188 | long l=System.currentTimeMillis(); 189 | String url="mqqapi://wallet/open?src_type=web&viewtype=0&version=1&view=7&entry=1&seq=" + l; 190 | Intent intent2=new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 191 | intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 192 | context.startActivity(intent2); 193 | } 194 | 195 | // PayHelperUtils.sendmsg(context, "启动成功"+l); 196 | } catch (Exception e) { 197 | PayHelperUtils.sendmsg(context, "StartQQReceived异常"+e.getMessage()); 198 | } 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/QQHook.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | 4 | 5 | import com.tools.payhelper.utils.PayHelperUtils; 6 | import com.tools.payhelper.utils.StringUtils; 7 | 8 | import android.app.Activity; 9 | import android.content.Context; 10 | import android.content.Intent; 11 | import de.robv.android.xposed.XC_MethodHook; 12 | import de.robv.android.xposed.XposedBridge; 13 | import de.robv.android.xposed.XposedHelpers; 14 | 15 | /** 16 | * 17 | 18 | * @ClassName: QQHook 19 | 20 | * @Description: TODO(这里用一句话描述这个类的作用) 21 | 22 | * @author SuXiaoliang 23 | 24 | * @date 2018年6月23日 下午1:26:39 25 | 26 | * 27 | */ 28 | 29 | public class QQHook { 30 | 31 | public static String BILLRECEIVED_ACTION = "com.tools.payhelper.billreceived"; 32 | 33 | public void hook(final ClassLoader classLoader,final Context context) { 34 | try { 35 | XposedHelpers.findAndHookMethod("com.tencent.mobileqq.app.MessageHandlerUtils", classLoader, "a", 36 | "com.tencent.mobileqq.app.QQAppInterface", 37 | "com.tencent.mobileqq.data.MessageRecord", Boolean.TYPE, new XC_MethodHook() { 38 | @Override 39 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 40 | byte[] msgData= (byte[]) XposedHelpers.getObjectField(param.args[1], "msgData"); 41 | Class clazz=XposedHelpers.findClass("com.tencent.mobileqq.structmsg.StructMsgFactory", classLoader); 42 | Object object=XposedHelpers.callStaticMethod(clazz, "a", msgData); 43 | if(object!=null){ 44 | String xml=(String) XposedHelpers.callMethod(object, "getXml"); 45 | XposedBridge.log(xml); 46 | PayHelperUtils.sendmsg(context, xml); 47 | if(xml.contains("转账金额")){ 48 | XposedBridge.log("=========qq钱包收到订单start========"); 49 | String tradeno=StringUtils.getTextCenter(xml, "transId=", "\""); 50 | String money=StringUtils.getTextCenter(xml, "转账金额:", ""); 51 | String mark=StringUtils.getTextCenter(xml, "转账留言:", ""); 52 | XposedBridge.log("收到qq支付订单:"+tradeno+"=="+money+"=="+mark); 53 | Intent broadCastIntent = new Intent(); 54 | broadCastIntent.putExtra("bill_no", tradeno); 55 | broadCastIntent.putExtra("bill_money", money); 56 | broadCastIntent.putExtra("bill_mark", mark); 57 | broadCastIntent.putExtra("bill_type", "qq"); 58 | broadCastIntent.setAction(BILLRECEIVED_ACTION); 59 | context.sendBroadcast(broadCastIntent); 60 | XposedBridge.log("=========qq钱包收到订单start========"); 61 | } 62 | } 63 | } 64 | } 65 | ); 66 | XposedHelpers.findAndHookMethod("com.tencent.mobileqq.activity.SplashActivity", classLoader, "doOnResume", 67 | new XC_MethodHook() { 68 | @Override 69 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 70 | Activity activity=(Activity) param.thisObject; 71 | String loginid=PayHelperUtils.getQQLoginId(activity); 72 | PayHelperUtils.sendLoginId(loginid, "qq", activity); 73 | } 74 | } 75 | ); 76 | } catch (Exception e) { 77 | PayHelperUtils.sendmsg(context, "QQHook异常"); 78 | } 79 | /*XposedHelpers.findAndHookMethod("com.tencent.mobileqq.activity.SplashActivity", classLoader, "doOnCreate", 80 | Bundle.class, new XC_MethodHook() { 81 | @Override 82 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 83 | Activity activity=(Activity) param.thisObject; 84 | PayHelperUtils.sendmsg(activity, "SplashActivity---->doOnCreate"); 85 | ClassLoader walletClassLoader = (ClassLoader) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.tencent.mobileqq.pluginsdk.PluginStatic", classLoader), "getOrCreateClassLoader", context, "qwallet_plugin.apk"); 86 | if(walletClassLoader!=null){ 87 | PayHelperUtils.sendmsg(context, "walletClassLoader不为空"); 88 | }else{ 89 | PayHelperUtils.sendmsg(context, "walletClassLoader为空"); 90 | } 91 | } 92 | } 93 | ); 94 | XposedHelpers.findAndHookMethod("com.tencent.mobileqq.activity.JumpActivity", classLoader, "doOnCreate", 95 | Bundle.class, new XC_MethodHook() { 96 | @Override 97 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 98 | Activity activity=(Activity) param.thisObject; 99 | PayHelperUtils.sendmsg(activity, "JumpActivity---->doOnCreate"); 100 | Intent intent=(Intent) XposedHelpers.callMethod(param.thisObject, "getIntent"); 101 | String url=intent.getDataString(); 102 | PayHelperUtils.sendmsg(activity, url); 103 | } 104 | } 105 | );*/ 106 | } 107 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/QQPlugHook.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | 4 | 5 | import java.util.Map; 6 | import java.util.Map.Entry; 7 | 8 | import org.json.JSONObject; 9 | 10 | import com.tools.payhelper.utils.PayHelperUtils; 11 | import com.tools.payhelper.utils.QQDBManager; 12 | import com.tools.payhelper.utils.QrCodeBean; 13 | 14 | import android.app.Activity; 15 | import android.content.Context; 16 | import android.content.Intent; 17 | import android.os.Bundle; 18 | import android.text.TextUtils; 19 | import android.view.View; 20 | import android.widget.Button; 21 | import de.robv.android.xposed.XC_MethodHook; 22 | import de.robv.android.xposed.XposedBridge; 23 | import de.robv.android.xposed.XposedHelpers; 24 | 25 | /** 26 | * 27 | 28 | * @ClassName: QQPlugHook 29 | 30 | * @Description: TODO(这里用一句话描述这个类的作用) 31 | 32 | * @author SuXiaoliang 33 | 34 | * @date 2018年6月23日 下午1:26:46 35 | 36 | * 37 | */ 38 | 39 | public class QQPlugHook { 40 | 41 | public static String QRCODERECEIVED_ACTION = "com.tools.payhelper.qrcodereceived"; 42 | 43 | public void hook(final ClassLoader classLoader) { 44 | XposedHelpers.findAndHookMethod("com.tenpay.sdk.activity.QrcodePayActivity", classLoader, "onCreate", 45 | Bundle.class, new XC_MethodHook() { 46 | @Override 47 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 48 | XposedBridge.log("=========qq钱包打开付款start========"); 49 | Activity activity=(Activity) param.thisObject; 50 | // PayHelperUtils.sendmsg(activity, "QrcodePayActivity---->>onCreate"); 51 | XposedHelpers.setIntField(param.thisObject, "n", 1); 52 | XposedHelpers.setBooleanField(param.thisObject, "o", true); 53 | XposedHelpers.callMethod(param.thisObject, "d"); 54 | View view=new View(activity); 55 | view.setId(2131363428); 56 | XposedHelpers.callMethod(param.thisObject, "onClick", view); 57 | XposedBridge.log("=========qq钱包打开付款end========"); 58 | } 59 | } 60 | ); 61 | 62 | XposedHelpers.findAndHookMethod("com.tenpay.sdk.activity.QrcodeSettingActivity", classLoader, "onCreate", 63 | Bundle.class, new XC_MethodHook() { 64 | @Override 65 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 66 | XposedBridge.log("=========qq钱包设置金额start========"); 67 | Activity activity=(Activity) param.thisObject; 68 | QQDBManager qqdbManager=new QQDBManager(activity); 69 | QrCodeBean qrCodeBean=qqdbManager.GetQQMark(); 70 | String money=qrCodeBean.getMoney(); 71 | String mark=qrCodeBean.getMark(); 72 | if(!TextUtils.isEmpty(money) && !TextUtils.isEmpty(mark)){ 73 | qqdbManager.updateOrder(money, mark); 74 | Object d= XposedHelpers.getObjectField(param.thisObject, "d"); 75 | XposedHelpers.callMethod(d, "setText",money); 76 | Object e= XposedHelpers.getObjectField(param.thisObject, "e"); 77 | XposedHelpers.callMethod(e, "setText",mark); 78 | Button c= (Button) XposedHelpers.getObjectField(param.thisObject, "c"); 79 | c.performClick(); 80 | } 81 | XposedBridge.log("=========qq钱包设置金额end========"); 82 | } 83 | } 84 | ); 85 | /*XposedHelpers.findAndHookMethod("com.tenpay.sdk.activity.NetBaseActivity", classLoader, "a", 86 | String.class,Map.class, new XC_MethodHook() { 87 | @Override 88 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 89 | Activity activity=(Activity) param.thisObject; 90 | Map map=(Map) param.args[1]; 91 | String url=(String) param.args[0]; 92 | StringBuffer buffer=new StringBuffer(); 93 | for (Entry entry : map.entrySet()) { 94 | buffer.append(entry.getKey()); 95 | buffer.append("="); 96 | buffer.append(entry.getValue()); 97 | buffer.append("&"); 98 | } 99 | PayHelperUtils.sendmsg(activity, "NetBaseActivity---->>a"); 100 | PayHelperUtils.sendmsg(activity, url+buffer.substring(0, buffer.toString().length()-1)); 101 | } 102 | } 103 | ); 104 | XposedHelpers.findAndHookMethod("com.tenpay.sdk.h.y", classLoader, "c", 105 | String.class, new XC_MethodHook() { 106 | @Override 107 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 108 | String header=(String) param.args[0]; 109 | XposedBridge.log(header); 110 | } 111 | } 112 | ); 113 | XposedHelpers.findAndHookMethod("com.tenpay.sdk.activity.QrcodePayActivity", classLoader, "a", 114 | String.class,JSONObject.class, new XC_MethodHook() { 115 | @Override 116 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 117 | Activity activity=(Activity) param.thisObject; 118 | JSONObject jsonObject=(JSONObject) param.args[1]; 119 | PayHelperUtils.sendmsg(activity, jsonObject.toString()); 120 | } 121 | } 122 | );*/ 123 | XposedHelpers.findAndHookMethod("com.tenpay.sdk.activity.QrcodePayActivity", classLoader, "c", 124 | String.class, new XC_MethodHook() { 125 | @Override 126 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 127 | XposedBridge.log("=========qq钱包生成完成start========"); 128 | Activity activity=(Activity) param.thisObject; 129 | String payurl="https://i.qianbao.qq.com/wallet/sqrcode.htm?m=tenpay&f=wallet&"; 130 | 131 | String u= (String) XposedHelpers.getObjectField(param.thisObject, "eb"); 132 | String n= (String) XposedHelpers.getObjectField(param.thisObject, "ec"); 133 | String ac= (String) param.args[0]; 134 | payurl+="u="+u+"&a=1"+"&n="+n+"&ac="+ac; 135 | 136 | String money=(String) XposedHelpers.getObjectField(param.thisObject, "aa"); 137 | String mark=(String) XposedHelpers.getObjectField(param.thisObject, "ab"); 138 | 139 | if(!TextUtils.isEmpty(money) && !TextUtils.isEmpty(mark) && ac.length()>64){ 140 | XposedBridge.log("调用增加数据方法==>QQ"); 141 | Intent broadCastIntent = new Intent(); 142 | broadCastIntent.putExtra("money", money+""); 143 | broadCastIntent.putExtra("mark", mark); 144 | broadCastIntent.putExtra("type", "qq"); 145 | broadCastIntent.putExtra("payurl", payurl); 146 | broadCastIntent.setAction(QRCODERECEIVED_ACTION); 147 | activity.sendBroadcast(broadCastIntent); 148 | int activitys=PayHelperUtils.isActivityTop(activity); 149 | if(activitys>2){ 150 | activity.finish(); 151 | } 152 | } 153 | XposedBridge.log("=========qq钱包生成完成end========"); 154 | } 155 | } 156 | ); 157 | } 158 | 159 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/SettingActivity.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | import com.tools.payhelper.utils.AbSharedUtil; 4 | 5 | import android.app.Activity; 6 | import android.os.Bundle; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.view.WindowManager; 11 | import android.widget.Button; 12 | import android.widget.EditText; 13 | import android.widget.RelativeLayout; 14 | import android.widget.Toast; 15 | 16 | /** 17 | * 18 | 19 | * @ClassName: SettingActivity 20 | 21 | * @Description: TODO(这里用一句话描述这个类的作用) 22 | 23 | * @author SuXiaoliang 24 | 25 | * @date 2018年6月23日 下午1:26:51 26 | 27 | * 28 | */ 29 | public class SettingActivity extends Activity implements OnClickListener{ 30 | 31 | private EditText et_returnurl,et_notifyurl,et_signkey,et_wxid; 32 | private Button bt_save,bt_back; 33 | private RelativeLayout rl_back; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 39 | setContentView(R.layout.activity_setting); 40 | et_returnurl=(EditText) findViewById(R.id.returnurl); 41 | et_notifyurl=(EditText) findViewById(R.id.notifyurl); 42 | et_signkey=(EditText) findViewById(R.id.signkey); 43 | et_wxid=(EditText) findViewById(R.id.et_wxid); 44 | if(!TextUtils.isEmpty(AbSharedUtil.getString(getApplicationContext(), "returnurl"))){ 45 | et_returnurl.setText(AbSharedUtil.getString(getApplicationContext(), "returnurl")); 46 | } 47 | if(!TextUtils.isEmpty(AbSharedUtil.getString(getApplicationContext(), "notifyurl"))){ 48 | et_notifyurl.setText(AbSharedUtil.getString(getApplicationContext(), "notifyurl")); 49 | } 50 | if(!TextUtils.isEmpty(AbSharedUtil.getString(getApplicationContext(), "signkey"))){ 51 | et_signkey.setText(AbSharedUtil.getString(getApplicationContext(), "signkey")); 52 | } 53 | if(!TextUtils.isEmpty(AbSharedUtil.getString(getApplicationContext(), "account"))){ 54 | et_wxid.setText(AbSharedUtil.getString(getApplicationContext(), "account")); 55 | } 56 | 57 | bt_save=(Button) findViewById(R.id.save); 58 | bt_back=(Button) findViewById(R.id.back); 59 | rl_back=(RelativeLayout) findViewById(R.id.rl_back); 60 | bt_back.setOnClickListener(this); 61 | bt_save.setOnClickListener(this); 62 | rl_back.setOnClickListener(this); 63 | } 64 | @Override 65 | protected void onDestroy() { 66 | super.onDestroy(); 67 | } 68 | @Override 69 | protected void onResume() { 70 | super.onResume(); 71 | } 72 | @Override 73 | public void onClick(View v) { 74 | switch (v.getId()) { 75 | case R.id.save: 76 | String returnurl=et_returnurl.getText().toString(); 77 | // if(TextUtils.isEmpty(returnurl)){ 78 | // Toast.makeText(getApplicationContext(), "同步跳转地址不能为空!", Toast.LENGTH_LONG).show(); 79 | // return; 80 | // }else{ 81 | AbSharedUtil.putString(getApplicationContext(), "returnurl", returnurl); 82 | // } 83 | String notifyurl=et_notifyurl.getText().toString(); 84 | // if(TextUtils.isEmpty(notifyurl)){ 85 | // Toast.makeText(getApplicationContext(), "异步通知地址不能为空!", Toast.LENGTH_LONG).show(); 86 | // return; 87 | // }else{ 88 | AbSharedUtil.putString(getApplicationContext(), "notifyurl", notifyurl); 89 | // } 90 | String signkey=et_signkey.getText().toString(); 91 | // if(TextUtils.isEmpty(signkey)){ 92 | // Toast.makeText(getApplicationContext(), "signkey不能为空!", Toast.LENGTH_LONG).show(); 93 | // return; 94 | // }else{ 95 | AbSharedUtil.putString(getApplicationContext(), "signkey", signkey); 96 | // } 97 | String wxid=et_wxid.getText().toString(); 98 | if(!TextUtils.isEmpty(wxid)){ 99 | AbSharedUtil.putString(getApplicationContext(), "account", wxid); 100 | } 101 | Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_LONG).show(); 102 | finish(); 103 | break; 104 | case R.id.back: 105 | finish(); 106 | break; 107 | case R.id.rl_back: 108 | finish(); 109 | break; 110 | default: 111 | break; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/WebServer.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.json.JSONObject; 8 | 9 | import com.tools.payhelper.utils.AbSharedUtil; 10 | import com.tools.payhelper.utils.BitmapUtil; 11 | import com.tools.payhelper.utils.DBManager; 12 | import com.tools.payhelper.utils.LogUtils; 13 | import com.tools.payhelper.utils.OrderBean; 14 | import com.tools.payhelper.utils.PayHelperUtils; 15 | import com.tools.payhelper.utils.QrCodeBean; 16 | 17 | import android.content.Context; 18 | import android.graphics.Bitmap; 19 | import android.text.TextUtils; 20 | import fi.iki.elonen.NanoHTTPD; 21 | 22 | /** 23 | * 24 | 25 | * @ClassName: WebServer 26 | 27 | * @Description: TODO(这里用一句话描述这个类的作用) 28 | 29 | * @author SuXiaoliang 30 | 31 | * @date 2018年6月23日 下午1:26:56 32 | 33 | * 34 | */ 35 | public class WebServer extends NanoHTTPD { 36 | 37 | public static final String TAG = WebServer.class.getSimpleName(); 38 | private static final String REQUEST_ROOT = "/"; 39 | private static final String REQUEST_WECHAT = "/wechat"; 40 | private static final String REQUEST_GETPAY = "/getpay"; 41 | private static final String REQUEST_QUERY = "/query"; 42 | private static final String REQUEST_GETRESULT = "/getresult"; 43 | public static String MSGRECEIVED_ACTION = "com.tools.payhelper.msgreceived"; 44 | private Context context; 45 | 46 | public WebServer(Context context,int serverport) { 47 | super(serverport); 48 | this.context = context; 49 | } 50 | 51 | @Override 52 | public Response serve(IHTTPSession session) { 53 | LogUtils.d("OnRequest: " + session.getUri()); 54 | try { 55 | if (REQUEST_ROOT.equals(session.getUri())) { 56 | return responseRootPage(session); 57 | } else if (REQUEST_WECHAT.equals(session.getUri())) { 58 | @SuppressWarnings("deprecation") 59 | Map params = session.getParms(); 60 | String money = params.get("money"); 61 | String mark = params.get("mark"); 62 | String type=params.get("type"); 63 | if(type==null || type.equals("")){ 64 | type="wechat"; 65 | } 66 | double m=Double.parseDouble(money); 67 | if(type.equals("alipay")){ 68 | if(m>50000){ 69 | return responseText(session, "支付宝最大支持单笔50000元支付!"); 70 | } 71 | }else if(type.equals("wechat")){ 72 | if(m>15000){ 73 | return responseText(session, "微信最大支持单笔15000元支付!"); 74 | } 75 | }else if(type.equals("qq")){ 76 | if(m>30000){ 77 | return responseText(session, "QQ最大支持单笔30000元支付!"); 78 | } 79 | if(mark.length()>12){ 80 | return responseText(session, "QQ备注长度不能超过12位!"); 81 | } 82 | } 83 | 84 | if(type.equals("alipay") && !PayHelperUtils.isAppRunning(context, "com.eg.android.AlipayGphone")){ 85 | PayHelperUtils.startAPP(context, "com.eg.android.AlipayGphone"); 86 | }else if(type.equals("wechat") && !PayHelperUtils.isAppRunning(context, "com.tencent.mm")){ 87 | PayHelperUtils.startAPP(context, "com.tencent.mm"); 88 | }else if(type.equals("qq") && !PayHelperUtils.isAppRunning(context, "com.tencent.mobileqq")){ 89 | PayHelperUtils.startAPP(context, "com.tencent.mobileqq"); 90 | } 91 | 92 | List qrCodeBeans=new ArrayList(); 93 | DBManager dbManager=new DBManager(CustomApplcation.getInstance().getApplicationContext()); 94 | PayHelperUtils.sendAppMsg(money, mark, type, context); 95 | int times=0; 96 | while (times<30 && qrCodeBeans.size()==0) { 97 | qrCodeBeans=dbManager.FindQrCodes(money, mark, type); 98 | times++; 99 | Thread.sleep(500); 100 | } 101 | if(qrCodeBeans.size()==0){ 102 | PayHelperUtils.startAPP(); 103 | return responseText(session,"获取超时...."); 104 | }else{ 105 | String payurl=qrCodeBeans.get(0).getPayurl(); 106 | PayHelperUtils.startAPP(); 107 | return responseQRCode(session, payurl,mark); 108 | } 109 | } else if (REQUEST_GETPAY.equals(session.getUri())) { 110 | @SuppressWarnings("deprecation") 111 | JSONObject jsonObject=new JSONObject(); 112 | Map params = session.getParms(); 113 | String money = params.get("money"); 114 | String mark = params.get("mark"); 115 | String type=params.get("type"); 116 | if(type==null || type.equals("")){ 117 | type="wechat"; 118 | } 119 | String account=""; 120 | double m=Double.parseDouble(money); 121 | if(type.equals("alipay")){ 122 | account=AbSharedUtil.getString(context, "alipay"); 123 | if(m>50000){ 124 | jsonObject.put("msg", "支付宝最大支持单笔50000元支付!"); 125 | return responseJson(session,jsonObject.toString()); 126 | } 127 | }else if(type.equals("wechat")){ 128 | account=AbSharedUtil.getString(context, "wechat"); 129 | if(m>15000){ 130 | jsonObject.put("msg", "微信最大支持单笔15000元支付!"); 131 | return responseJson(session,jsonObject.toString()); 132 | } 133 | }else if(type.equals("qq")){ 134 | account=AbSharedUtil.getString(context, "qq"); 135 | if(m>30000){ 136 | return responseText(session, "QQ最大支持单笔30000元支付!"); 137 | } 138 | if(mark.length()>12){ 139 | return responseText(session, "QQ备注长度不能超过12位!"); 140 | } 141 | } 142 | 143 | if(type.equals("alipay") && !PayHelperUtils.isAppRunning(context, "com.eg.android.AlipayGphone")){ 144 | PayHelperUtils.startAPP(context, "com.eg.android.AlipayGphone"); 145 | }else if(type.equals("wechat") && !PayHelperUtils.isAppRunning(context, "com.tencent.mm")){ 146 | PayHelperUtils.startAPP(context, "com.tencent.mm"); 147 | }else if(type.equals("qq") && !PayHelperUtils.isAppRunning(context, "com.tencent.mobileqq")){ 148 | PayHelperUtils.startAPP(context, "com.tencent.mobileqq"); 149 | } 150 | 151 | List qrCodeBeans=new ArrayList(); 152 | DBManager dbManager=new DBManager(CustomApplcation.getInstance().getApplicationContext()); 153 | PayHelperUtils.sendAppMsg(money, mark, type, context); 154 | int times=0; 155 | while (times<30 && qrCodeBeans.size()==0) { 156 | qrCodeBeans=dbManager.FindQrCodes(money, mark, type); 157 | times++; 158 | Thread.sleep(500); 159 | } 160 | 161 | LogUtils.d("size = " + qrCodeBeans.size()); 162 | 163 | if(qrCodeBeans.size()==0){ 164 | PayHelperUtils.startAPP(); 165 | jsonObject.put("msg", "获取超时"); 166 | return responseJson(session,jsonObject.toString()); 167 | }else{ 168 | String payurl=qrCodeBeans.get(0).getPayurl(); 169 | PayHelperUtils.startAPP(); 170 | jsonObject.put("msg", "获取成功"); 171 | jsonObject.put("payurl", payurl); 172 | jsonObject.put("mark", mark); 173 | jsonObject.put("money", money); 174 | jsonObject.put("type", type); 175 | if(!TextUtils.isEmpty(account)){ 176 | jsonObject.put("account", account); 177 | } 178 | 179 | LogUtils.d(jsonObject.toString()); 180 | return responseJson(session,jsonObject.toString()); 181 | } 182 | } else if (REQUEST_QUERY.equals(session.getUri())) { 183 | @SuppressWarnings("deprecation") 184 | Map params = session.getParms(); 185 | String mark = params.get("no"); 186 | List orderBeans=new ArrayList(); 187 | DBManager dbManager=new DBManager(CustomApplcation.getInstance().getApplicationContext()); 188 | orderBeans=dbManager.FindOrders(mark); 189 | if(orderBeans!=null && orderBeans.size()>0){ 190 | String dt=orderBeans.get(0).getDt(); 191 | String paytime=PayHelperUtils.stampToDate(dt); 192 | return responseText(session,"当前订单已支付,支付时间:"+paytime+"...."); 193 | }else{ 194 | return responseText(session,"当前订单未支付...."); 195 | } 196 | } else if (REQUEST_GETRESULT.equals(session.getUri())) { 197 | @SuppressWarnings("deprecation") 198 | Map params = session.getParms(); 199 | String mark = params.get("trade_no"); 200 | List orderBeans=new ArrayList(); 201 | DBManager dbManager=new DBManager(CustomApplcation.getInstance().getApplicationContext()); 202 | orderBeans=dbManager.FindOrders(mark); 203 | JSONObject jsonObject=new JSONObject(); 204 | String returnurl=AbSharedUtil.getString(context, "returnurl"); 205 | if(orderBeans!=null && orderBeans.size()>0){ 206 | String dt=orderBeans.get(0).getDt(); 207 | String money=orderBeans.get(0).getMoney(); 208 | String paytime=PayHelperUtils.stampToDate(dt); 209 | jsonObject.put("msg", "支付成功"); 210 | jsonObject.put("paytime", paytime); 211 | jsonObject.put("money", money); 212 | if(!TextUtils.isEmpty(returnurl)){ 213 | jsonObject.put("returnurl", returnurl); 214 | } 215 | return responseJson(session, jsonObject.toString()); 216 | }else{ 217 | jsonObject.put("msg", "未支付"); 218 | return responseJson(session, jsonObject.toString()); 219 | } 220 | }else{ 221 | return response404(session, session.getUri()); 222 | } 223 | } catch (Exception e) { 224 | return response404(session, e.getMessage()); 225 | } 226 | } 227 | 228 | public Response responseRootPage(IHTTPSession session) { 229 | StringBuilder builder = new StringBuilder(); 230 | builder.append(""); 231 | builder.append("Hello World!"); 232 | builder.append("\n"); 233 | return newFixedLengthResponse(builder.toString()); 234 | } 235 | 236 | public Response responseQRCode(IHTTPSession session,String QRText,String no) { 237 | Bitmap bitmap=BitmapUtil.createQRImage(QRText, 240, null); 238 | String imgbase64=BitmapUtil.bitmapToBase64(bitmap); 239 | imgbase64="\"data:image/gif;base64," + imgbase64 + "\""; 240 | StringBuilder builder = new StringBuilder(); 241 | builder.append(""); 242 | builder.append("
"); 243 | builder.append("二维码生成测试
"); 244 | builder.append(""); 246 | builder.append("
"); 247 | String url="http://"+session.getHeaders().get("host"); 248 | builder.append("获取成功,查询订单是否支付:查询

"); 249 | builder.append("
"); 250 | builder.append("\n"); 251 | LogUtils.i(builder.toString()); 252 | return newFixedLengthResponse(Response.Status.OK, "text/html;charset=UTF-8", builder.toString()); 253 | } 254 | public Response responseText(IHTTPSession session, String text) { 255 | StringBuilder builder = new StringBuilder(); 256 | builder.append(""); 257 | builder.append("
"); 258 | builder.append(text); 259 | builder.append("
"); 260 | builder.append("\n"); 261 | LogUtils.i(builder.toString()); 262 | return newFixedLengthResponse(Response.Status.OK, "text/html;charset=UTF-8", builder.toString()); 263 | } 264 | public Response responseJson(IHTTPSession session, String json) { 265 | LogUtils.i(json); 266 | return newFixedLengthResponse(Response.Status.OK, "application/json;charset=UTF-8", json); 267 | } 268 | 269 | public Response response404(IHTTPSession session, String url) { 270 | StringBuilder builder = new StringBuilder(); 271 | builder.append(""); 272 | builder.append("Sorry, Can't Found " + url + " !"); 273 | builder.append("\n"); 274 | return newFixedLengthResponse(builder.toString()); 275 | } 276 | 277 | protected String getQuotaStr(String text) { 278 | return "\"" + text + "\""; 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/WechatHook.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import org.json.JSONObject; 6 | 7 | import com.tools.payhelper.utils.PayHelperUtils; 8 | import com.tools.payhelper.utils.XmlToJson; 9 | 10 | import android.app.Activity; 11 | import android.content.ContentValues; 12 | import android.content.Context; 13 | import android.content.Intent; 14 | import android.text.TextUtils; 15 | import android.widget.Button; 16 | import de.robv.android.xposed.XC_MethodHook; 17 | import de.robv.android.xposed.XposedBridge; 18 | import de.robv.android.xposed.XposedHelpers; 19 | import de.robv.android.xposed.XC_MethodHook.MethodHookParam; 20 | 21 | /** 22 | * 23 | 24 | * @ClassName: WechatHook 25 | 26 | * @Description: TODO(这里用一句话描述这个类的作用) 27 | 28 | * @author SuXiaoliang 29 | 30 | * @date 2018年6月23日 下午1:27:01 31 | 32 | * 33 | */ 34 | public class WechatHook { 35 | 36 | public static String BILLRECEIVED_ACTION = "com.tools.payhelper.billreceived"; 37 | public static String QRCODERECEIVED_ACTION = "com.tools.payhelper.qrcodereceived"; 38 | 39 | protected void hook(final ClassLoader appClassLoader,final Context context) { 40 | // TODO Auto-generated method stub 41 | 42 | XposedHelpers.findAndHookMethod("com.tencent.wcdb.database.SQLiteDatabase",appClassLoader, "insert",String.class, String.class, ContentValues.class, 43 | new XC_MethodHook() { 44 | 45 | @Override 46 | protected void beforeHookedMethod(MethodHookParam param) 47 | throws Throwable { 48 | try { 49 | ContentValues contentValues = (ContentValues) param.args[2]; 50 | String tableName = (String) param.args[0]; 51 | if (TextUtils.isEmpty(tableName) || !tableName.equals("message")) { 52 | return; 53 | } 54 | Integer type = contentValues.getAsInteger("type"); 55 | if (null == type) { 56 | return; 57 | } 58 | if(type==318767153){ 59 | JSONObject msg=new XmlToJson.Builder(contentValues.getAsString("content")).build().getJSONObject("msg"); 60 | XposedBridge.log(msg.toString()); 61 | if(!msg.toString().contains("零钱提现")){ 62 | XposedBridge.log("=========微信收到订单start========"); 63 | String money=msg.getJSONObject("appmsg").getJSONObject("mmreader").getJSONObject("template_detail").getJSONObject("line_content").getJSONObject("topline").getJSONObject("value").getString("word"); 64 | money=money.replace("¥", ""); 65 | String mark=msg.getJSONObject("appmsg").getJSONObject("mmreader").getJSONObject("template_detail").getJSONObject("line_content").getJSONObject("lines").getJSONArray("line").getJSONObject(0).getJSONObject("value").getString("word"); 66 | String pay_outtradeno=""; 67 | try { 68 | pay_outtradeno=msg.getJSONObject("appmsg").getJSONObject("ext_pay_info").getString("pay_outtradeno"); 69 | } catch (Exception e) { 70 | pay_outtradeno=msg.getJSONObject("appmsg").getString("template_id"); 71 | } 72 | XposedBridge.log("收到微信支付订单:"+pay_outtradeno+"=="+money+"=="+mark); 73 | Intent broadCastIntent = new Intent(); 74 | broadCastIntent.putExtra("bill_no", pay_outtradeno); 75 | broadCastIntent.putExtra("bill_money", money); 76 | broadCastIntent.putExtra("bill_mark", mark); 77 | broadCastIntent.putExtra("bill_type", "wechat"); 78 | broadCastIntent.setAction(BILLRECEIVED_ACTION); 79 | context.sendBroadcast(broadCastIntent); 80 | XposedBridge.log("=========微信收到订单start========"); 81 | } 82 | } 83 | } catch (Exception e) { 84 | XposedBridge.log(e.getMessage()); 85 | } 86 | } 87 | 88 | @Override 89 | protected void afterHookedMethod(MethodHookParam param) 90 | throws Throwable { 91 | } 92 | }); 93 | 94 | //hook请求参数 95 | // try { 96 | // XposedHelpers.findAndHookMethod("com.tencent.mm.wallet_core.c.i",appClassLoader, "E", Map.class, 97 | // new XC_MethodHook() { 98 | // 99 | // @Override 100 | // protected void beforeHookedMethod(MethodHookParam param) 101 | // throws Throwable { 102 | // Map map=(Map) param.args[0]; 103 | // XposedBridge.log(map.toString()); 104 | // } 105 | // 106 | // @Override 107 | // protected void afterHookedMethod(MethodHookParam param) 108 | // throws Throwable { 109 | // } 110 | // }); 111 | // } catch (Exception e) { 112 | // } 113 | 114 | //hook更改请求参数 115 | // try { 116 | // XposedHelpers.findAndHookConstructor("com.tencent.mm.plugin.collect.b.s", appClassLoader, double.class,String.class,String.class,new XC_MethodHook() { 117 | // 118 | // @Override 119 | // protected void beforeHookedMethod(MethodHookParam param) 120 | // throws Throwable { 121 | // String mark="备注啦啦啦"; 122 | // param.args[2]=mark; 123 | // XposedBridge.log("拦截请求修改参数:mark="+param.args[2].toString()+"money="+String.valueOf(param.args[0])+"type="+param.args[1].toString()); 124 | // } 125 | // 126 | // @Override 127 | // protected void afterHookedMethod(MethodHookParam param) 128 | // throws Throwable { 129 | // } 130 | // }); 131 | // } catch (Exception e) { 132 | // } 133 | //获取请求返回数据 134 | /*try { 135 | Class bfj=XposedHelpers.findClass("com.tencent.mm.protocal.c.bfj", appClassLoader); 136 | XposedHelpers.findAndHookMethod("com.tencent.mm.platformtools.aa",appClassLoader, "b", bfj, 137 | new XC_MethodHook() { 138 | 139 | @Override 140 | protected void beforeHookedMethod(MethodHookParam param) 141 | throws Throwable { 142 | } 143 | 144 | @Override 145 | protected void afterHookedMethod(MethodHookParam param) 146 | throws Throwable { 147 | if(param.args[0]!=null){ 148 | String result=param.getResult().toString(); 149 | XposedBridge.log("拦截返回数据=="+result); 150 | } 151 | } 152 | }); 153 | 154 | } catch (Exception e) { 155 | }*/ 156 | try { 157 | Class clazz=XposedHelpers.findClass("com.tencent.mm.plugin.collect.b.s", appClassLoader); 158 | XposedBridge.hookAllMethods(clazz, "a", new XC_MethodHook() { 159 | 160 | @Override 161 | protected void beforeHookedMethod(MethodHookParam param) 162 | throws Throwable { 163 | } 164 | 165 | @Override 166 | protected void afterHookedMethod(MethodHookParam param) 167 | throws Throwable { 168 | XposedBridge.log("=========微信生成完成start========"); 169 | if(PayHelperUtils.getVerName(context).equals("6.6.7")){ 170 | Field moneyField = XposedHelpers.findField(param.thisObject.getClass(), "hUL"); 171 | double money = (double) moneyField.get(param.thisObject); 172 | 173 | Field markField = XposedHelpers.findField(param.thisObject.getClass(), "desc"); 174 | String mark = (String) markField.get(param.thisObject); 175 | 176 | Field payurlField = XposedHelpers.findField(param.thisObject.getClass(), "hUK"); 177 | String payurl = (String) payurlField.get(param.thisObject); 178 | 179 | XposedBridge.log(money+" "+mark+" "+payurl); 180 | 181 | XposedBridge.log("调用增加数据方法==>微信"); 182 | Intent broadCastIntent = new Intent(); 183 | broadCastIntent.putExtra("money", money+""); 184 | broadCastIntent.putExtra("mark", mark); 185 | broadCastIntent.putExtra("type", "wechat"); 186 | broadCastIntent.putExtra("payurl", payurl); 187 | broadCastIntent.setAction(QRCODERECEIVED_ACTION); 188 | context.sendBroadcast(broadCastIntent); 189 | }else if(PayHelperUtils.getVerName(context).equals("6.6.6")){ 190 | Field moneyField = XposedHelpers.findField(param.thisObject.getClass(), "llG"); 191 | double money = (double) moneyField.get(param.thisObject); 192 | 193 | Field markField = XposedHelpers.findField(param.thisObject.getClass(), "desc"); 194 | String mark = (String) markField.get(param.thisObject); 195 | 196 | Field payurlField = XposedHelpers.findField(param.thisObject.getClass(), "llF"); 197 | String payurl = (String) payurlField.get(param.thisObject); 198 | 199 | XposedBridge.log(money+" "+mark+" "+payurl); 200 | 201 | XposedBridge.log("调用增加数据方法==>微信"); 202 | Intent broadCastIntent = new Intent(); 203 | broadCastIntent.putExtra("money", money+""); 204 | broadCastIntent.putExtra("mark", mark); 205 | broadCastIntent.putExtra("type", "wechat"); 206 | broadCastIntent.putExtra("payurl", payurl); 207 | broadCastIntent.setAction(QRCODERECEIVED_ACTION); 208 | context.sendBroadcast(broadCastIntent); 209 | } 210 | XposedBridge.log("=========微信生成完成end========"); 211 | } 212 | }); 213 | 214 | } catch (Exception e) { 215 | PayHelperUtils.sendmsg(context, "异常"+e.getMessage()); 216 | } 217 | try { 218 | XposedHelpers.findAndHookMethod("com.tencent.mm.plugin.collect.ui.CollectCreateQRCodeUI",appClassLoader, "initView", 219 | new XC_MethodHook() { 220 | 221 | @Override 222 | protected void beforeHookedMethod(MethodHookParam param) 223 | throws Throwable { 224 | } 225 | 226 | @Override 227 | protected void afterHookedMethod(MethodHookParam param) 228 | throws Throwable { 229 | //微信6.6.7新版修复 230 | XposedBridge.log("=========微信设置金额start========"); 231 | if(PayHelperUtils.getVerName(context).equals("6.6.7")){ 232 | Intent intent = ((Activity) param.thisObject).getIntent(); 233 | String mark=intent.getStringExtra("mark"); 234 | String money=intent.getStringExtra("money"); 235 | //获取WalletFormView控件 236 | Field WalletFormViewField = XposedHelpers.findField(param.thisObject.getClass(), "hXD"); 237 | Object WalletFormView = WalletFormViewField.get(param.thisObject); 238 | Class WalletFormViewClass=XposedHelpers.findClass("com.tencent.mm.wallet_core.ui.formview.WalletFormView", appClassLoader); 239 | //获取金额控件 240 | Field AefField = XposedHelpers.findField(WalletFormViewClass, "uZy"); 241 | Object AefView = AefField.get(WalletFormView); 242 | //call设置金额方法 243 | XposedHelpers.callMethod(AefView, "setText", money); 244 | //call设置备注方法 245 | Class clazz=XposedHelpers.findClass("com.tencent.mm.plugin.collect.ui.CollectCreateQRCodeUI", appClassLoader); 246 | XposedHelpers.callStaticMethod(clazz, "a", param.thisObject,mark); 247 | XposedHelpers.callStaticMethod(clazz, "c", param.thisObject); 248 | //点击确定 249 | Button click=(Button)XposedHelpers.callMethod(param.thisObject, "findViewById",2131756838); 250 | click.performClick(); 251 | }else if(PayHelperUtils.getVerName(context).equals("6.6.6")){ 252 | Intent intent = ((Activity) param.thisObject).getIntent(); 253 | String mark=intent.getStringExtra("mark"); 254 | String money=intent.getStringExtra("money"); 255 | //获取WalletFormView控件 256 | Field WalletFormViewField = XposedHelpers.findField(param.thisObject.getClass(), "loz"); 257 | Object WalletFormView = WalletFormViewField.get(param.thisObject); 258 | Class WalletFormViewClass=XposedHelpers.findClass("com.tencent.mm.wallet_core.ui.formview.WalletFormView", appClassLoader); 259 | //获取金额控件 260 | Field AefField = XposedHelpers.findField(WalletFormViewClass, "Aef"); 261 | Object AefView = AefField.get(WalletFormView); 262 | //call设置金额方法 263 | XposedHelpers.callMethod(AefView, "setText", money); 264 | //call设置备注方法 265 | Class clazz=XposedHelpers.findClass("com.tencent.mm.plugin.collect.ui.CollectCreateQRCodeUI", appClassLoader); 266 | XposedHelpers.callStaticMethod(clazz, "a", param.thisObject,mark); 267 | XposedHelpers.callStaticMethod(clazz, "c", param.thisObject); 268 | //点击确定 269 | Button click=(Button)XposedHelpers.callMethod(param.thisObject, "findViewById",2131756780); 270 | click.performClick(); 271 | } 272 | XposedBridge.log("=========微信设置金额start========"); 273 | // Field MoneyField = XposedHelpers.findField(WalletFormViewClass, "jyA"); 274 | // Object MoneyView = MoneyField.get(WalletFormView); 275 | //// 276 | // Field MarkField = XposedHelpers.findField(WalletFormViewClass, "qdA"); 277 | // Object MarkView = MarkField.get(WalletFormView); 278 | // 279 | // Field qdDField = XposedHelpers.findField(WalletFormViewClass, "qdD"); 280 | // Object qdDView = qdDField.get(WalletFormView); 281 | 282 | // XposedHelpers.callMethod(MoneyView, "setText", "1"); 283 | // XposedHelpers.callMethod(MarkView, "setText", "2"); 284 | // XposedHelpers.callMethod(qdDView, "setText", "3"); 285 | 286 | // Button click=(Button)XposedHelpers.callMethod(param.thisObject, "findViewById",2131756780); 287 | // click.performClick(); 288 | // Field quRenField = XposedHelpers.findField(param.thisObject.getClass(), "loA"); 289 | // Button quRenButton = (Button) quRenField.get(param.thisObject); 290 | // quRenButton.performClick(); 291 | // XposedHelpers.callMethod(constructor.newInstance(0.01d,"1","test")); 292 | // Class clazz = XposedHelpers.findClass("com.tencent.mm.plugin.collect.b.s",context.getClassLoader()); 293 | // Constructor constructor = clazz.getConstructor(double.class,String.class,String.class); 294 | // Object object=constructor.newInstance(10,"1","test"); 295 | // Class test = XposedHelpers.findClass("com.tencent.mm.wallet_core.ui.WalletBaseUI", context.getClassLoader()); 296 | // XposedHelpers.callMethod(test.newInstance(), "a", object,true,true); 297 | } 298 | }); 299 | } catch (Exception e) { 300 | PayHelperUtils.sendmsg(context, "异常"+e.getMessage()); 301 | } 302 | try { 303 | // hook获取loginid 304 | XposedHelpers.findAndHookMethod("com.tencent.mm.ui.LauncherUI", appClassLoader, "onResume", 305 | new XC_MethodHook() { 306 | @Override 307 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 308 | String loginid=PayHelperUtils.getWechatLoginId(context); 309 | loginid=loginid.replace("+86", ""); 310 | PayHelperUtils.sendLoginId(loginid, "wechat", context); 311 | } 312 | }); 313 | } catch (Exception e) { 314 | } 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/http/CookieJarManager.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.http; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import okhttp3.Cookie; 7 | import okhttp3.CookieJar; 8 | 9 | 10 | /** 11 | *

Cookie管理类

12 | */ 13 | public class CookieJarManager implements CookieJar { 14 | 15 | /** 16 | * 保存cookie 17 | */ 18 | private List mCookieList = new ArrayList(); 19 | /** 20 | * 这里注册需要你保存Cookie的URL 21 | */ 22 | private String COOKIE_URL[] = new String[]{ 23 | }; 24 | 25 | /** 26 | * 是否保存cookie 27 | * 28 | * @param url 29 | * 请求URL 30 | * @return true 保存 31 | */ 32 | private boolean isSaveCookie(String url){ 33 | for(String cookieUrl : COOKIE_URL){ 34 | if(url.contains(cookieUrl)){ 35 | return true; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | 42 | @Override 43 | public void saveFromResponse(okhttp3.HttpUrl httpUrl, List list) { 44 | String url = httpUrl.uri().toString(); 45 | if(isSaveCookie(url)){ 46 | // mCookieList.clear(); // 这里只保存一次cookie 47 | mCookieList.addAll(list); 48 | } 49 | } 50 | 51 | @Override 52 | public List loadForRequest(okhttp3.HttpUrl httpUrl) { 53 | return mCookieList; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/http/HttpUrl.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.http; 2 | 3 | public class HttpUrl { 4 | 5 | public static final String BASE_URL = "http://127.0.0.1:8080/"; 6 | 7 | /** 8 | * 登录 9 | */ 10 | public static final String URL_LOGIN = BASE_URL + "login"; 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/http/ParamField.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.http; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.FIELD) 10 | public @interface ParamField { 11 | String value() default ""; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/http/request/HttpParams.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.http.request; 2 | 3 | import java.io.Serializable; 4 | 5 | 6 | 7 | public interface HttpParams extends Serializable { 8 | 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/http/result/BaseResult.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.http.result; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | *

返回数据基类

8 | */ 9 | public class BaseResult implements Serializable { 10 | 11 | public Error error; 12 | public String value; 13 | 14 | @Override 15 | public String toString() { 16 | return "BaseResult{" + 17 | "error=" + error + 18 | ", value='" + value + '\'' + 19 | '}'; 20 | } 21 | 22 | public static class Error { 23 | public String errorCode; 24 | public String message; 25 | public String errorType; 26 | @Override 27 | public String toString() { 28 | return "Error{" + 29 | "errorCode='" + errorCode + '\'' + 30 | ", message='" + message + '\'' + 31 | ", errorType='" + errorType + '\'' + 32 | '}'; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/tcp/TcpCheck.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.tcp; 2 | 3 | public class TcpCheck { 4 | 5 | public Verify data; 6 | 7 | public static class Verify { 8 | public String key; 9 | public Verify(String key) { 10 | this.key = key; 11 | } 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/tcp/TcpConnection.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.tcp; 2 | 3 | import com.tools.payhelper.utils.JsonHelper; 4 | import com.tools.payhelper.utils.LogUtils; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.BufferedWriter; 8 | import java.io.DataInputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.io.OutputStreamWriter; 13 | import java.io.PrintWriter; 14 | import java.io.Reader; 15 | import java.io.Writer; 16 | import java.net.Socket; 17 | import java.net.SocketTimeoutException; 18 | 19 | 20 | public class TcpConnection extends Thread { 21 | 22 | // auto.1899pay.com 8011 23 | 24 | private Socket mSocket; 25 | private BufferedReader mBufferedReader = null; 26 | private PrintWriter mPrintWriter = null; 27 | 28 | private String mIpAddress; 29 | private int mIpPort; 30 | private String mVerify; 31 | 32 | private OnTcpResultListener mOnTcpResultListener; 33 | private long mLastHeartBeatTimestamp; 34 | private HeartBeatThread mHeartBeatThread; 35 | 36 | private static TcpConnection instance = null; 37 | public static TcpConnection getInstance() { 38 | if (instance == null) { 39 | instance = new TcpConnection(); 40 | } 41 | return instance; 42 | } 43 | 44 | public void init(String address, int port, String verify) { 45 | this.mIpAddress = address; 46 | this.mIpPort = port; 47 | this.mVerify = verify; 48 | this.mLastHeartBeatTimestamp = System.currentTimeMillis(); 49 | } 50 | 51 | @Override 52 | public void run() { 53 | super.run(); 54 | connect(); 55 | try { 56 | while (mSocket != null && !mSocket.isClosed() && mSocket.isConnected()) { 57 | if (!mSocket.isInputShutdown()) { 58 | try { 59 | InputStream inputStream = mSocket.getInputStream(); 60 | DataInputStream input = new DataInputStream(inputStream); 61 | byte[] b = new byte[2 * 1024]; 62 | int length = 0; 63 | while ((length = input.read(b)) != -1) { 64 | String msg = new String(b, 0, length, "utf-8").replace("\0", ""); 65 | LogUtils.d("length = " + length + ", msg = " + msg); 66 | if (!msg.isEmpty() && mOnTcpResultListener != null) { 67 | mOnTcpResultListener.onReceive(msg); 68 | } 69 | } 70 | } catch (SocketTimeoutException e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | } 75 | } catch (Exception e) { 76 | LogUtils.e(e.toString()); 77 | e.printStackTrace(); 78 | mOnTcpResultListener.onFailed(e.toString()); 79 | } 80 | } 81 | 82 | private void connect() { 83 | try { 84 | mSocket = new Socket(mIpAddress, mIpPort); 85 | mSocket.setSoTimeout(3000); 86 | mBufferedReader = new BufferedReader(new InputStreamReader(mSocket 87 | .getInputStream())); 88 | mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter( 89 | mSocket.getOutputStream())), true); 90 | LogUtils.i("Connect success"); 91 | if (mOnTcpResultListener != null) { 92 | mOnTcpResultListener.onConnected(); 93 | } 94 | 95 | // verify 96 | String data = JsonHelper.toJson(VerifyData.createVerifyData(mVerify)); 97 | send(data); 98 | LogUtils.i("Send verify success, " + data); 99 | 100 | // heart beat 101 | mHeartBeatThread = new HeartBeatThread(); 102 | mHeartBeatThread.start(); 103 | } catch (IOException e) { 104 | LogUtils.e(e.toString()); 105 | mOnTcpResultListener.onFailed(e.toString()); 106 | e.printStackTrace(); 107 | } 108 | } 109 | 110 | private void closeInputStream(InputStream inputStream) { 111 | if (inputStream != null) { 112 | try { 113 | inputStream.close(); 114 | } catch (IOException e) { 115 | e.printStackTrace(); 116 | } 117 | } 118 | } 119 | 120 | private void closeReader(Reader reader) { 121 | if (reader != null) { 122 | try { 123 | reader.close(); 124 | } catch (IOException e) { 125 | e.printStackTrace(); 126 | } 127 | } 128 | } 129 | 130 | private void closeWriter(Writer writer) { 131 | if (writer != null) { 132 | try { 133 | writer.close(); 134 | } catch (IOException e) { 135 | e.printStackTrace(); 136 | } 137 | } 138 | } 139 | 140 | private void closeSocket(Socket socket) { 141 | if (socket != null) { 142 | try { 143 | socket.close(); 144 | } catch (IOException e) { 145 | e.printStackTrace(); 146 | } 147 | } 148 | } 149 | 150 | public interface OnTcpResultListener { 151 | 152 | void onConnected(); 153 | 154 | void onReceive(String data); 155 | 156 | void onFailed(String error); 157 | } 158 | 159 | public OnTcpResultListener getOnTcpResultListener() { 160 | return mOnTcpResultListener; 161 | } 162 | 163 | public void setOnTcpResultListener(OnTcpResultListener listener) { 164 | this.mOnTcpResultListener = listener; 165 | } 166 | 167 | public void send(String msg) { 168 | LogUtils.d("msg: " + msg); 169 | if (mPrintWriter != null) { 170 | mPrintWriter.write(msg); 171 | mPrintWriter.flush(); 172 | } 173 | } 174 | 175 | public void close() { 176 | LogUtils.i("close"); 177 | closeReader(mBufferedReader); 178 | closeWriter(mPrintWriter); 179 | closeSocket(mSocket); 180 | if (mHeartBeatThread != null) { 181 | mHeartBeatThread.interrupt(); 182 | mHeartBeatThread = null; 183 | } 184 | instance = null; 185 | } 186 | 187 | private class HeartBeatThread extends Thread { 188 | 189 | @Override 190 | public void run() { 191 | super.run(); 192 | while (mSocket != null && !mSocket.isClosed() && mSocket.isConnected()) { 193 | long currentTimestamp = System.currentTimeMillis(); 194 | if (mLastHeartBeatTimestamp + 20 * 1000 < currentTimestamp ) { 195 | String data = JsonHelper.toJson(VerifyData.createHeartBeatData()); 196 | send(data); 197 | LogUtils.d("Heart beat, " + data); 198 | mLastHeartBeatTimestamp = currentTimestamp; 199 | } 200 | } 201 | } 202 | } 203 | 204 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/tcp/TcpSettingActivity.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.tcp; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.text.TextUtils; 6 | import android.view.View; 7 | import android.view.View.OnClickListener; 8 | import android.view.WindowManager; 9 | import android.widget.Button; 10 | import android.widget.EditText; 11 | import android.widget.RelativeLayout; 12 | import android.widget.Toast; 13 | 14 | import com.tools.payhelper.R; 15 | import com.tools.payhelper.utils.AbSharedUtil; 16 | 17 | 18 | public class TcpSettingActivity extends Activity implements OnClickListener { 19 | 20 | private EditText et_ip, et_port, et_verify; 21 | private Button bt_save, bt_back; 22 | private RelativeLayout rl_back; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 28 | setContentView(R.layout.activity_tcp_setting); 29 | et_ip = (EditText) findViewById(R.id.et_ip); 30 | et_port = (EditText) findViewById(R.id.et_port); 31 | et_verify = (EditText) findViewById(R.id.et_verify); 32 | if (!TextUtils.isEmpty(AbSharedUtil.getString(getApplicationContext(), "tcp_ip"))) { 33 | et_ip.setText(AbSharedUtil.getString(getApplicationContext(), "tcp_ip")); 34 | } else { 35 | et_ip.setText("auto.1899pay.com"); 36 | } 37 | if (AbSharedUtil.getInt(getApplicationContext(), "tcp_port") != 0) { 38 | et_port.setText("" + AbSharedUtil.getInt(getApplicationContext(), "tcp_port")); 39 | } else { 40 | et_port.setText("8011"); 41 | } 42 | if (!TextUtils.isEmpty(AbSharedUtil.getString(getApplicationContext(), "tcp_verify"))) { 43 | et_verify.setText("" + AbSharedUtil.getString(getApplicationContext(), "tcp_verify")); 44 | } else { 45 | et_verify.setText("5"); 46 | } 47 | 48 | bt_save = (Button) findViewById(R.id.save); 49 | bt_back = (Button) findViewById(R.id.back); 50 | rl_back = (RelativeLayout) findViewById(R.id.rl_back); 51 | bt_back.setOnClickListener(this); 52 | bt_save.setOnClickListener(this); 53 | rl_back.setOnClickListener(this); 54 | } 55 | 56 | @Override 57 | protected void onDestroy() { 58 | super.onDestroy(); 59 | } 60 | 61 | @Override 62 | protected void onResume() { 63 | super.onResume(); 64 | } 65 | 66 | @Override 67 | public void onClick(View v) { 68 | switch (v.getId()) { 69 | case R.id.save: 70 | String tcp_ip = et_ip.getText().toString(); 71 | if (TextUtils.isEmpty(tcp_ip)) { 72 | Toast.makeText(getApplicationContext(), "IP不能为空!", Toast.LENGTH_LONG).show(); 73 | return; 74 | } else { 75 | AbSharedUtil.putString(getApplicationContext(), "tcp_ip", tcp_ip); 76 | } 77 | String tcp_port = et_port.getText().toString(); 78 | if (TextUtils.isEmpty(tcp_port)) { 79 | Toast.makeText(getApplicationContext(), "PORT不能为空!", Toast.LENGTH_LONG).show(); 80 | return; 81 | } else { 82 | AbSharedUtil.putInt(getApplicationContext(), "tcp_port", Integer.valueOf(tcp_port)); 83 | } 84 | String tcp_verify = et_verify.getText().toString(); 85 | if (TextUtils.isEmpty(tcp_verify)) { 86 | Toast.makeText(getApplicationContext(), "认证信息不能为空!", Toast.LENGTH_LONG).show(); 87 | return; 88 | } else { 89 | AbSharedUtil.putString(getApplicationContext(), "tcp_verify", tcp_verify); 90 | } 91 | Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_LONG).show(); 92 | finish(); 93 | break; 94 | case R.id.back: 95 | finish(); 96 | break; 97 | case R.id.rl_back: 98 | finish(); 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/tcp/VerifyData.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.tcp; 2 | 3 | import com.tools.payhelper.utils.JsonHelper; 4 | 5 | /** 6 | * @since Create on 2018/11/8. 7 | */ 8 | public class VerifyData { 9 | 10 | public static final int TYPE_Frist = 9; //第一次验证 11 | public static final int TYPE_Ping = 0; //心跳 20s/次 12 | public static final int TYPE_KeyOK = 1; //验证成功 13 | public static final int TYPE_KeyNO = 2; //验证失败 14 | public static final int TYPE_ResOK = 3; //获取数据成功 15 | public static final int TYPE_ResNO = 4; //获取数据失败 16 | public static final int TYPE_Interactive = 5; // 交互 17 | public static final int TYPE_SuccTransaction = 6; // 付款的订单 18 | 19 | 20 | /** 21 | * 服务器-》 首次验证key 返回 Type 22 | * 客户端-》 验证Type 状态 23 | */ 24 | public int type; 25 | public int restype; 26 | public String res; 27 | /** 28 | * 例:服务器-》 InOutData:{ money:1000,mark:k18dsfsd0,type:alipay} 29 | * 客户端-》 InOutData: {data:{key:asdasda}} 等待服务器的数据,并发送心跳IntoData:{ping:0} 30 | */ 31 | public InOut InOutData; 32 | 33 | public static class InOut { 34 | public String key; 35 | public String data; 36 | 37 | public static InOut verify(String verify) { 38 | InOut d = new InOut(); 39 | d.key = verify; 40 | return d; 41 | } 42 | public static InOut heartBeat() { 43 | InOut d = new InOut(); 44 | d.data = "0"; 45 | return d; 46 | } 47 | public static InOut pay(String data) { 48 | InOut d = new InOut(); 49 | d.data = data; 50 | return d; 51 | } 52 | } 53 | 54 | public static class PayResult { 55 | public String no; 56 | public String money; 57 | public String mark; 58 | public String type; 59 | public String dt; 60 | public String account; 61 | public String sign; 62 | 63 | public PayResult(String no, String money, String mark, String type, String dt, String account, String sign) { 64 | this.no = no; 65 | this.money = money; 66 | this.mark = mark; 67 | this.type = type; 68 | this.dt = dt; 69 | this.account = account; 70 | this.sign = sign; 71 | } 72 | } 73 | 74 | public static class PayCodeData { 75 | public String msg; 76 | public String payurl; 77 | public String mark; 78 | public String money; 79 | public String account; 80 | } 81 | 82 | public static VerifyData createVerifyData(String verify) { 83 | VerifyData data = new VerifyData(); 84 | data.type = TYPE_Frist; 85 | data.InOutData = InOut.verify(verify); 86 | return data; 87 | } 88 | 89 | public static VerifyData createHeartBeatData() { 90 | VerifyData data = new VerifyData(); 91 | data.type = TYPE_Ping; 92 | data.InOutData = InOut.heartBeat(); 93 | return data; 94 | } 95 | 96 | public static VerifyData createPayData(String payData) { 97 | VerifyData data = new VerifyData(); 98 | data.type = TYPE_Interactive; 99 | data.InOutData = InOut.pay(payData); 100 | return data; 101 | } 102 | 103 | public static VerifyData createPayResultData(String no, String money, String mark, String type, String dt, String account, String sign) { 104 | VerifyData data = new VerifyData(); 105 | data.type = TYPE_SuccTransaction; 106 | data.InOutData = InOut.pay(JsonHelper.toJson(new PayResult(no, money, mark, type, dt, account, sign))); 107 | return data; 108 | } 109 | 110 | 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/threadpool/ThreadPoolProxy.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.threadpool; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.Future; 6 | import java.util.concurrent.LinkedBlockingDeque; 7 | import java.util.concurrent.RejectedExecutionHandler; 8 | import java.util.concurrent.ThreadFactory; 9 | import java.util.concurrent.ThreadPoolExecutor; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | public class ThreadPoolProxy { 13 | 14 | ThreadPoolExecutor mExecutor; 15 | private int mCorePoolSize; 16 | private int mMaximumPoolSize; 17 | 18 | /** 19 | * @param corePoolSize 核心池的大小 20 | * @param maximumPoolSize 最大线程数 21 | */ 22 | public ThreadPoolProxy(int corePoolSize, int maximumPoolSize) { 23 | mCorePoolSize = corePoolSize; 24 | mMaximumPoolSize = maximumPoolSize; 25 | } 26 | 27 | /** 28 | * 初始化ThreadPoolExecutor 29 | * 双重检查加锁,只有在第一次实例化的时候才启用同步机制,提高了性能 30 | */ 31 | private void initThreadPoolExecutor() { 32 | if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated()) { 33 | synchronized (ThreadPoolProxy.class) { 34 | if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated()) { 35 | long keepAliveTime = 3000; 36 | TimeUnit unit = TimeUnit.MILLISECONDS; 37 | BlockingQueue workQueue = new LinkedBlockingDeque<>(); 38 | ThreadFactory threadFactory = Executors.defaultThreadFactory(); 39 | RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy(); 40 | 41 | mExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, keepAliveTime, unit, workQueue, 42 | threadFactory, handler); 43 | } 44 | } 45 | } 46 | } 47 | /** 48 | 执行任务和提交任务的区别? 49 | 1.有无返回值 50 | execute->没有返回值 51 | submit-->有返回值 52 | 2.Future的具体作用? 53 | 1.有方法可以接收一个任务执行完成之后的结果,其实就是get方法,get方法是一个阻塞方法 54 | 2.get方法的签名抛出了异常===>可以处理任务执行过程中可能遇到的异常 55 | */ 56 | /** 57 | * 执行任务 58 | */ 59 | public void execute(Runnable task) { 60 | initThreadPoolExecutor(); 61 | mExecutor.execute(task); 62 | } 63 | 64 | /** 65 | * 提交任务 66 | */ 67 | public Future submit(Runnable task) { 68 | initThreadPoolExecutor(); 69 | return mExecutor.submit(task); 70 | } 71 | 72 | /** 73 | * 移除任务 74 | */ 75 | public void remove(Runnable task) { 76 | initThreadPoolExecutor(); 77 | mExecutor.remove(task); 78 | } 79 | 80 | public ThreadPoolExecutor getExecutor() { 81 | return mExecutor; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/threadpool/ThreadPoolProxyFactory.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.threadpool; 2 | 3 | public class ThreadPoolProxyFactory { 4 | static ThreadPoolProxy mNormalThreadPoolProxy; 5 | static ThreadPoolProxy mDownLoadThreadPoolProxy; 6 | 7 | /** 8 | * 得到普通线程池代理对象mNormalThreadPoolProxy 9 | */ 10 | public static ThreadPoolProxy getNormalThreadPoolProxy() { 11 | if (mNormalThreadPoolProxy == null) { 12 | synchronized (ThreadPoolProxyFactory.class) { 13 | if (mNormalThreadPoolProxy == null) { 14 | mNormalThreadPoolProxy = new ThreadPoolProxy(5, 5); 15 | } 16 | } 17 | } 18 | return mNormalThreadPoolProxy; 19 | } 20 | 21 | /** 22 | * 得到下载线程池代理对象mDownLoadThreadPoolProxy 23 | */ 24 | public static ThreadPoolProxy getDownLoadThreadPoolProxy() { 25 | if (mDownLoadThreadPoolProxy == null) { 26 | synchronized (ThreadPoolProxyFactory.class) { 27 | if (mDownLoadThreadPoolProxy == null) { 28 | mDownLoadThreadPoolProxy = new ThreadPoolProxy(3, 3); 29 | } 30 | } 31 | } 32 | return mDownLoadThreadPoolProxy; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/AbSharedUtil.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.content.SharedPreferences.Editor; 6 | 7 | //TODO: Auto-generated Javadoc 8 | 9 | /** 10 | * © 2012 amsoft.cn 11 | * 名称:AbSharedUtil.java 12 | * 描述:保存到 SharedPreferences 的数据. 13 | * 14 | * @author 还如一梦中 15 | * @version v1.0 16 | * @date:2014-10-09 下午11:52:13 17 | */ 18 | public class AbSharedUtil { 19 | 20 | private static final String SHARED_PATH = "bbplayer"; 21 | 22 | public static SharedPreferences getDefaultSharedPreferences(Context context) { 23 | return context.getSharedPreferences(SHARED_PATH, Context.MODE_PRIVATE); 24 | } 25 | 26 | public static void putInt(Context context,String key, int value) { 27 | SharedPreferences sharedPreferences = getDefaultSharedPreferences(context); 28 | Editor edit = sharedPreferences.edit(); 29 | edit.putInt(key, value); 30 | edit.commit(); 31 | } 32 | 33 | public static int getInt(Context context,String key) { 34 | SharedPreferences sharedPreferences = getDefaultSharedPreferences(context); 35 | return sharedPreferences.getInt(key, 0); 36 | } 37 | 38 | public static void putString(Context context,String key, String value) { 39 | SharedPreferences sharedPreferences = getDefaultSharedPreferences(context); 40 | Editor edit = sharedPreferences.edit(); 41 | edit.putString(key, value); 42 | edit.commit(); 43 | } 44 | 45 | public static String getString(Context context,String key) { 46 | SharedPreferences sharedPreferences = getDefaultSharedPreferences(context); 47 | return sharedPreferences.getString(key,null); 48 | } 49 | 50 | public static void putBoolean(Context context,String key, boolean value) { 51 | SharedPreferences sharedPreferences = getDefaultSharedPreferences(context); 52 | Editor edit = sharedPreferences.edit(); 53 | edit.putBoolean(key, value); 54 | edit.commit(); 55 | } 56 | 57 | public static boolean getBoolean(Context context,String key,boolean defValue) { 58 | SharedPreferences sharedPreferences = getDefaultSharedPreferences(context); 59 | return sharedPreferences.getBoolean(key,defValue); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/BitmapUtil.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import static android.graphics.Color.BLACK; 4 | 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.IOException; 7 | import java.util.HashMap; 8 | import java.util.Hashtable; 9 | import java.util.Map; 10 | 11 | import com.google.zxing.BarcodeFormat; 12 | import com.google.zxing.EncodeHintType; 13 | import com.google.zxing.MultiFormatWriter; 14 | import com.google.zxing.WriterException; 15 | import com.google.zxing.common.BitMatrix; 16 | import com.google.zxing.qrcode.QRCodeWriter; 17 | import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 18 | 19 | import android.annotation.SuppressLint; 20 | import android.graphics.Bitmap; 21 | import android.graphics.Bitmap.CompressFormat; 22 | import android.graphics.Canvas; 23 | import android.util.Base64; 24 | 25 | /** 26 | * Created by 1 on 2017/5/19. 27 | */ 28 | public class BitmapUtil { 29 | //生成二维码图片(不带图片) 30 | public static Bitmap createQRCode(String url, int widthAndHeight) 31 | throws WriterException { 32 | Hashtable hints = new Hashtable(); 33 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 34 | BitMatrix matrix = new MultiFormatWriter().encode("lvu", 35 | BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight); 36 | 37 | int width = matrix.getWidth(); 38 | int height = matrix.getHeight(); 39 | int[] pixels = new int[width * height]; 40 | //画黑点 41 | for (int y = 0; y < height; y++) { 42 | for (int x = 0; x < width; x++) { 43 | if (matrix.get(x, y)) { 44 | pixels[y * width + x] = BLACK; //0xff000000 45 | } 46 | } 47 | } 48 | Bitmap bitmap = Bitmap.createBitmap(width, height, 49 | Bitmap.Config.ARGB_8888); 50 | bitmap.setPixels(pixels, 0, width, 0, 0, width, height); 51 | return bitmap; 52 | } 53 | 54 | 55 | //带图片的二维码 56 | public static Bitmap createQRImage(String content, int heightPix, Bitmap logoBm) { 57 | try { 58 | //配置参数 59 | Map hints = new HashMap(); 60 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 61 | //容错级别 62 | hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 63 | // 图像数据转换,使用了矩阵转换 64 | BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, heightPix, heightPix, hints); 65 | int[] pixels = new int[heightPix * heightPix]; 66 | // 下面这里按照二维码的算法,逐个生成二维码的图片, 67 | // 两个for循环是图片横列扫描的结果 68 | for (int y = 0; y < heightPix; y++) { 69 | for (int x = 0; x < heightPix; x++) { 70 | if (bitMatrix.get(x, y)) { 71 | pixels[y * heightPix + x] = 0xff000000; 72 | } else { 73 | pixels[y * heightPix + x] = 0xffffffff; 74 | } 75 | } 76 | } 77 | 78 | // 生成二维码图片的格式,使用ARGB_8888 79 | Bitmap bitmap = Bitmap.createBitmap(heightPix, heightPix, Bitmap.Config.ARGB_8888); 80 | bitmap.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix); 81 | 82 | if (logoBm != null) { 83 | bitmap = addLogo(bitmap, logoBm); 84 | } 85 | 86 | //必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大! 87 | return bitmap; 88 | } catch (WriterException e) { 89 | e.printStackTrace(); 90 | } 91 | 92 | return null; 93 | } 94 | 95 | @SuppressLint("NewApi") 96 | public static String bitmapToBase64(Bitmap bitmap) { 97 | 98 | // 要返回的字符串 99 | String reslut = null; 100 | 101 | ByteArrayOutputStream baos = null; 102 | 103 | try { 104 | 105 | if (bitmap != null) { 106 | 107 | baos = new ByteArrayOutputStream(); 108 | /** 109 | * 压缩只对保存有效果bitmap还是原来的大小 110 | */ 111 | bitmap.compress(CompressFormat.JPEG, 30, baos); 112 | 113 | baos.flush(); 114 | baos.close(); 115 | // 转换为字节数组 116 | byte[] byteArray = baos.toByteArray(); 117 | 118 | // 转换为字符串 119 | reslut = Base64.encodeToString(byteArray, Base64.DEFAULT); 120 | } else { 121 | return null; 122 | } 123 | } catch (IOException e) { 124 | e.printStackTrace(); 125 | } finally { 126 | 127 | try { 128 | if (baos != null) { 129 | baos.close(); 130 | } 131 | } catch (IOException e) { 132 | e.printStackTrace(); 133 | } 134 | 135 | } 136 | return reslut; 137 | 138 | } 139 | 140 | /** 141 | * 在二维码中间添加Logo图案 142 | */ 143 | private static Bitmap addLogo(Bitmap src, Bitmap logo) { 144 | if (src == null) { 145 | return null; 146 | } 147 | 148 | if (logo == null) { 149 | return src; 150 | } 151 | 152 | //获取图片的宽高 153 | int srcWidth = src.getWidth(); 154 | int srcHeight = src.getHeight(); 155 | int logoWidth = logo.getWidth(); 156 | int logoHeight = logo.getHeight(); 157 | 158 | if (srcWidth == 0 || srcHeight == 0) { 159 | return null; 160 | } 161 | 162 | if (logoWidth == 0 || logoHeight == 0) { 163 | return src; 164 | } 165 | 166 | //logo大小为二维码整体大小的1/5 167 | float scaleFactor = srcWidth * 1.0f / 5 / logoWidth; 168 | Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); 169 | try { 170 | Canvas canvas = new Canvas(bitmap); 171 | canvas.drawBitmap(src, 0, 0, null); 172 | canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); 173 | canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null); 174 | 175 | canvas.save(Canvas.ALL_SAVE_FLAG); 176 | canvas.restore(); 177 | } catch (Exception e) { 178 | bitmap = null; 179 | e.getStackTrace(); 180 | } 181 | 182 | return bitmap; 183 | } 184 | 185 | 186 | } 187 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/CrashHandler.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.PrintWriter; 6 | import java.io.StringWriter; 7 | import java.io.Writer; 8 | import java.lang.Thread.UncaughtExceptionHandler; 9 | import java.lang.reflect.Field; 10 | import java.text.DateFormat; 11 | import java.text.SimpleDateFormat; 12 | import java.util.Date; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | import android.content.Context; 17 | import android.content.pm.PackageInfo; 18 | import android.content.pm.PackageManager; 19 | import android.content.pm.PackageManager.NameNotFoundException; 20 | import android.os.Build; 21 | import android.os.Environment; 22 | import android.os.Looper; 23 | import android.util.Log; 24 | 25 | /** 26 | * UncaughtException处理�?,当程序发生Uncaught异常的时�?,有该类来接管程序,并记录发送错误报�?. 27 | * 28 | * @author user 29 | * 30 | */ 31 | public class CrashHandler implements 32 | UncaughtExceptionHandler { 33 | 34 | public static final String TAG = "CrashHandler"; 35 | 36 | // 系统默认的UncaughtException处理�? 37 | private Thread.UncaughtExceptionHandler mDefaultHandler; 38 | // CrashHandler实例 39 | private static CrashHandler INSTANCE = new CrashHandler(); 40 | // 程序的Context对象 41 | private Context mContext; 42 | // 用来存储设备信息和异常信�? 43 | private Map infos = new HashMap(); 44 | 45 | // 用于格式化日�?,作为日志文件名的�?部分 46 | private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); 47 | 48 | /** 保证只有�?个CrashHandler实例 */ 49 | private CrashHandler() { 50 | 51 | } 52 | 53 | /** 获取CrashHandler实例 ,单例模式 */ 54 | public static CrashHandler getInstance() { 55 | return INSTANCE; 56 | } 57 | 58 | /** 59 | * 初始�? 60 | * 61 | * @param context 62 | */ 63 | public void init(Context context) { 64 | mContext = context; 65 | // 获取系统默认的UncaughtException处理�? 66 | mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); 67 | // 设置该CrashHandler为程序的默认处理�? 68 | Thread.setDefaultUncaughtExceptionHandler(this); 69 | } 70 | 71 | /** 72 | * 当UncaughtException发生时会转入该函数来处理 73 | */ 74 | @Override 75 | public void uncaughtException(Thread thread, Throwable ex) { 76 | if (!handleException(ex) && mDefaultHandler != null) { 77 | // 如果用户没有处理则让系统默认的异常处理器来处�? 78 | mDefaultHandler.uncaughtException(thread, ex); 79 | } else { 80 | try { 81 | Thread.sleep(3000); 82 | } catch (InterruptedException e) { 83 | Log.e(TAG, "error : ", e); 84 | } 85 | // �?出程�? 86 | android.os.Process.killProcess(android.os.Process.myPid()); 87 | System.exit(1); 88 | } 89 | } 90 | 91 | /** 92 | * 自定义错误处�?,收集错误信息 发�?�错误报告等操作均在此完�?. 93 | * 94 | * @param ex 95 | * @return true:如果处理了该异常信息;否则返回false. 96 | */ 97 | @SuppressWarnings("deprecation") 98 | private boolean handleException(Throwable ex) { 99 | if (ex == null) { 100 | return false; 101 | } 102 | // 使用Toast来显示异常信�? 103 | new Thread() { 104 | @Override 105 | public void run() { 106 | Looper.prepare(); 107 | Looper.loop(); 108 | } 109 | }.start(); 110 | // 收集设备参数信息 111 | collectDeviceInfo(mContext); 112 | // 保存日志文件 113 | saveCrashInfo2File(ex); 114 | android.os.Process.killProcess(android.os.Process.myPid()); 115 | // System.exit(0); 116 | return true; 117 | } 118 | 119 | /** 120 | * 收集设备参数信息 121 | * 122 | * @param ctx 123 | */ 124 | public void collectDeviceInfo(Context ctx) { 125 | try { 126 | PackageManager pm = ctx.getPackageManager(); 127 | PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), 128 | PackageManager.GET_ACTIVITIES); 129 | if (pi != null) { 130 | String versionName = pi.versionName == null ? "null" 131 | : pi.versionName; 132 | String versionCode = pi.versionCode + ""; 133 | infos.put("versionName", versionName); 134 | infos.put("versionCode", versionCode); 135 | } 136 | } catch (NameNotFoundException e) { 137 | Log.e(TAG, "an error occured when collect package info", e); 138 | } 139 | Field[] fields = Build.class.getDeclaredFields(); 140 | for (Field field : fields) { 141 | try { 142 | field.setAccessible(true); 143 | infos.put(field.getName(), field.get(null).toString()); 144 | Log.d(TAG, field.getName() + " : " + field.get(null)); 145 | } catch (Exception e) { 146 | Log.e(TAG, "an error occured when collect crash info", e); 147 | } 148 | } 149 | } 150 | 151 | /** 152 | * 保存错误信息到文件中 153 | * 154 | * @param ex 155 | * @return 返回文件名称,便于将文件传送到服务�? 156 | */ 157 | private String saveCrashInfo2File(Throwable ex) { 158 | 159 | StringBuffer sb = new StringBuffer(); 160 | for (Map.Entry entry : infos.entrySet()) { 161 | String key = entry.getKey(); 162 | String value = entry.getValue(); 163 | sb.append(key + "=" + value + "\n"); 164 | } 165 | Writer writer = new StringWriter(); 166 | PrintWriter printWriter = new PrintWriter(writer); 167 | ex.printStackTrace(printWriter); 168 | Throwable cause = ex.getCause(); 169 | while (cause != null) { 170 | cause.printStackTrace(printWriter); 171 | cause = cause.getCause(); 172 | } 173 | printWriter.close(); 174 | String result = writer.toString(); 175 | sb.append(result); 176 | try { 177 | long timestamp = System.currentTimeMillis(); 178 | String time = formatter.format(new Date()); 179 | String fileName = "crash-" + time + "-" + timestamp + ".log"; 180 | if (Environment.getExternalStorageState().equals( 181 | Environment.MEDIA_MOUNTED)) { 182 | String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/PayHelper/crash/"; 183 | File dir = new File(path); 184 | if (!dir.exists()) { 185 | dir.mkdirs(); 186 | } 187 | // // 文件传到服务�? 188 | // upload(Base64.encodeToString(sb.toString().getBytes(), 189 | // Base64.DEFAULT)); 190 | FileOutputStream fos = new FileOutputStream(path + fileName); 191 | fos.write(sb.toString().getBytes()); 192 | fos.close(); 193 | } 194 | return fileName; 195 | } catch (Exception e) { 196 | Log.e(TAG, "an error occured while writing file...", e); 197 | } 198 | return null; 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/DBHelper.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteOpenHelper; 6 | 7 | /** 8 | * 9 | 10 | * @ClassName: DBHelper 11 | 12 | * @Description: TODO(这里用一句话描述这个类的作用) 13 | 14 | * @author SuXiaoliang 15 | 16 | * @date 2018年6月23日 下午1:27:16 17 | 18 | * 19 | */ 20 | public class DBHelper extends SQLiteOpenHelper{ 21 | public DBHelper(Context context) { 22 | super(context, "trade.db", null, 1); 23 | } 24 | 25 | @Override 26 | public void onCreate(SQLiteDatabase db) { 27 | db.execSQL("CREATE TABLE IF NOT EXISTS qrcode" + 28 | "(_id INTEGER PRIMARY KEY AUTOINCREMENT, money varchar, mark varchar, type varchar, payurl varchar, dt varchar)"); 29 | db.execSQL("CREATE TABLE IF NOT EXISTS payorder" + 30 | "(_id INTEGER PRIMARY KEY AUTOINCREMENT, money varchar, mark varchar, type varchar, tradeno varchar, dt varchar, result varchar, time integer)"); 31 | db.execSQL("CREATE TABLE IF NOT EXISTS tradeno" + 32 | "(_id INTEGER PRIMARY KEY AUTOINCREMENT, tradeno varchar, status varchar)"); 33 | db.execSQL("CREATE TABLE IF NOT EXISTS config" + 34 | "(_id INTEGER PRIMARY KEY AUTOINCREMENT, name varchar, value varchar)"); 35 | } 36 | 37 | @Override 38 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 39 | // TODO Auto-generated method stub 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/DBManager.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.text.DecimalFormat; 4 | import java.util.ArrayList; 5 | 6 | import android.content.Context; 7 | import android.database.Cursor; 8 | import android.database.sqlite.SQLiteDatabase; 9 | 10 | /** 11 | * 12 | 13 | * @ClassName: DBManager 14 | 15 | * @Description: TODO(这里用一句话描述这个类的作用) 16 | 17 | * @author SuXiaoliang 18 | 19 | * @date 2018年6月23日 下午1:27:22 20 | 21 | * 22 | */ 23 | public class DBManager { 24 | private SQLiteDatabase db; 25 | private DBHelper helper; 26 | public DBManager(Context context){ 27 | helper = new DBHelper(context); 28 | db = helper.getWritableDatabase(); 29 | } 30 | 31 | public void addQrCode(QrCodeBean qrCodeBean) { 32 | db.beginTransaction();// 开始事务 33 | try { 34 | String dt=System.currentTimeMillis()/1000+""; 35 | db.execSQL("INSERT INTO qrcode VALUES(null,?,?,?,?,?)", new Object[] { qrCodeBean.getMoney(), qrCodeBean.getMark(), qrCodeBean.getType(), qrCodeBean.getPayurl(), dt }); 36 | db.setTransactionSuccessful();// 事务成功 37 | } finally { 38 | db.endTransaction();// 结束事务 39 | } 40 | } 41 | public void addOrder(OrderBean ordereBean) { 42 | db.beginTransaction();// 开始事务 43 | try { 44 | String dt=System.currentTimeMillis()/1000+""; 45 | db.execSQL("INSERT INTO payorder VALUES(null,?,?,?,?,?,?,?)", new Object[] { ordereBean.getMoney(), ordereBean.getMark(), ordereBean.getType(), ordereBean.getNo(), dt ,ordereBean.getResult() , ordereBean.getTime() }); 46 | db.setTransactionSuccessful();// 事务成功 47 | } finally { 48 | db.endTransaction();// 结束事务 49 | } 50 | } 51 | public void addTradeNo(String tradeNo,String status) { 52 | db.beginTransaction();// 开始事务 53 | try { 54 | db.execSQL("INSERT INTO tradeno VALUES(null,?,?)", new Object[] { tradeNo, status}); 55 | db.setTransactionSuccessful();// 事务成功 56 | } finally { 57 | db.endTransaction();// 结束事务 58 | } 59 | } 60 | 61 | public void addConfig(String name,String value) { 62 | db.beginTransaction();// 开始事务 63 | try { 64 | db.execSQL("INSERT INTO config VALUES(null,?,?)", new Object[] { name,value }); 65 | db.setTransactionSuccessful();// 事务成功 66 | } finally { 67 | db.endTransaction();// 结束事务 68 | } 69 | } 70 | 71 | public void updateConfig(String name,String value) { 72 | db.beginTransaction();// 开始事务 73 | try { 74 | db.execSQL("UPDATE config SET value=? WHERE name=?", new Object[] {value, name}); 75 | db.setTransactionSuccessful();// 事务成功 76 | } finally { 77 | db.endTransaction();// 结束事务 78 | } 79 | } 80 | 81 | public void saveOrUpdateConfig(String name,String value) { 82 | if(getConfig(name).equals("null")){ 83 | addConfig(name, value); 84 | }else{ 85 | updateConfig(name, value); 86 | } 87 | } 88 | 89 | public String getConfig(String name) { 90 | String sql = "SELECT * FROM config WHERE name='"+name+"'"; 91 | Cursor c = ExecSQLForCursor(sql); 92 | String value="null"; 93 | if(c.moveToNext()){ 94 | value=c.getString(c.getColumnIndex("value")); 95 | } 96 | c.close(); 97 | return value; 98 | } 99 | 100 | public boolean isExistTradeNo(String tradeNo) { 101 | boolean isExist=false; 102 | String sql = "SELECT * FROM tradeno WHERE tradeno='"+tradeNo+"'"; 103 | Cursor c = ExecSQLForCursor(sql); 104 | if(c.getCount()>0){ 105 | isExist=true; 106 | } 107 | c.close(); 108 | return isExist; 109 | } 110 | 111 | public boolean isNotifyTradeNo(String tradeNo) { 112 | boolean isExist=false; 113 | String sql = "SELECT * FROM tradeno WHERE tradeno='"+tradeNo+"'"; 114 | Cursor c = ExecSQLForCursor(sql); 115 | if(c.moveToNext()){ 116 | String status=c.getString(c.getColumnIndex("status")); 117 | if(status.equals("1")) 118 | isExist=true; 119 | } 120 | c.close(); 121 | return isExist; 122 | } 123 | 124 | public void updateTradeNo(String tradeNo,String status) { 125 | db.beginTransaction();// 开始事务 126 | try { 127 | db.execSQL("UPDATE tradeno SET status=? WHERE tradeno=?", new Object[] {status, tradeNo}); 128 | db.setTransactionSuccessful();// 事务成功 129 | } finally { 130 | db.endTransaction();// 结束事务 131 | } 132 | } 133 | 134 | public void updateOrder(String no,String result) { 135 | db.beginTransaction();// 开始事务 136 | try { 137 | db.execSQL("UPDATE payorder SET result=?,time=time+1 WHERE tradeno=?", new Object[] {result, no}); 138 | db.setTransactionSuccessful();// 事务成功 139 | } finally { 140 | db.endTransaction();// 结束事务 141 | } 142 | } 143 | 144 | public ArrayList FindQrCodes(String money,String mark,String type) { 145 | DecimalFormat df = new DecimalFormat("0.00"); 146 | money=df.format(Double.parseDouble(money)); 147 | String sql = "SELECT * FROM qrcode WHERE money =" + "'" + money + "' and mark='"+mark+"' and type='"+type+"'"; 148 | ArrayList list = new ArrayList(); 149 | Cursor c = ExecSQLForCursor(sql); 150 | while (c.moveToNext()) { 151 | QrCodeBean info = new QrCodeBean(); 152 | info.setMoney(c.getString(c.getColumnIndex("money"))); 153 | info.setMark(c.getString(c.getColumnIndex("mark"))); 154 | info.setType(c.getString(c.getColumnIndex("type"))); 155 | info.setPayurl(c.getString(c.getColumnIndex("payurl"))); 156 | info.setDt(c.getString(c.getColumnIndex("dt"))); 157 | list.add(info); 158 | } 159 | c.close(); 160 | return list; 161 | } 162 | public ArrayList FindQrCodes(String mark,String type) { 163 | String sql = "SELECT * FROM qrcode WHERE mark='"+mark+"'"; 164 | ArrayList list = new ArrayList(); 165 | Cursor c = ExecSQLForCursor(sql); 166 | while (c.moveToNext()) { 167 | QrCodeBean info = new QrCodeBean(); 168 | info.setMoney(c.getString(c.getColumnIndex("money"))); 169 | info.setMark(c.getString(c.getColumnIndex("mark"))); 170 | info.setType(c.getString(c.getColumnIndex("type"))); 171 | info.setPayurl(c.getString(c.getColumnIndex("payurl"))); 172 | info.setDt(c.getString(c.getColumnIndex("dt"))); 173 | list.add(info); 174 | } 175 | c.close(); 176 | return list; 177 | } 178 | public ArrayList FindOrders(String money,String mark,String type) { 179 | String sql = "SELECT * FROM payorder WHERE money =" + "'" + money + "' and mark='"+mark+"' and type='"+type+"'"; 180 | ArrayList list = new ArrayList(); 181 | Cursor c = ExecSQLForCursor(sql); 182 | while (c.moveToNext()) { 183 | OrderBean info = new OrderBean(); 184 | info.setMoney(c.getString(c.getColumnIndex("money"))); 185 | info.setMark(c.getString(c.getColumnIndex("mark"))); 186 | info.setType(c.getString(c.getColumnIndex("type"))); 187 | info.setNo(c.getString(c.getColumnIndex("tradeno"))); 188 | info.setDt(c.getString(c.getColumnIndex("dt"))); 189 | info.setResult(c.getString(c.getColumnIndex("result"))); 190 | info.setTime(c.getInt(c.getColumnIndex("time"))); 191 | list.add(info); 192 | } 193 | c.close(); 194 | return list; 195 | } 196 | public ArrayList FindOrders(String mark) { 197 | String sql = "SELECT * FROM payorder WHERE mark='"+mark+"'"; 198 | ArrayList list = new ArrayList(); 199 | Cursor c = ExecSQLForCursor(sql); 200 | while (c.moveToNext()) { 201 | OrderBean info = new OrderBean(); 202 | info.setMoney(c.getString(c.getColumnIndex("money"))); 203 | info.setMark(c.getString(c.getColumnIndex("mark"))); 204 | info.setType(c.getString(c.getColumnIndex("type"))); 205 | info.setNo(c.getString(c.getColumnIndex("tradeno"))); 206 | info.setDt(c.getString(c.getColumnIndex("dt"))); 207 | info.setResult(c.getString(c.getColumnIndex("result"))); 208 | info.setTime(c.getInt(c.getColumnIndex("time"))); 209 | list.add(info); 210 | } 211 | c.close(); 212 | return list; 213 | } 214 | public ArrayList FindOrdersByNo(String no) { 215 | String sql = "SELECT * FROM payorder WHERE tradeno='"+no+"'"; 216 | ArrayList list = new ArrayList(); 217 | Cursor c = ExecSQLForCursor(sql); 218 | while (c.moveToNext()) { 219 | OrderBean info = new OrderBean(); 220 | info.setMoney(c.getString(c.getColumnIndex("money"))); 221 | info.setMark(c.getString(c.getColumnIndex("mark"))); 222 | info.setType(c.getString(c.getColumnIndex("type"))); 223 | info.setNo(c.getString(c.getColumnIndex("tradeno"))); 224 | info.setDt(c.getString(c.getColumnIndex("dt"))); 225 | info.setResult(c.getString(c.getColumnIndex("result"))); 226 | info.setTime(c.getInt(c.getColumnIndex("time"))); 227 | list.add(info); 228 | } 229 | c.close(); 230 | return list; 231 | } 232 | public ArrayList FindAllOrders() { 233 | String sql = "SELECT * FROM payorder where result <> 'success' and time<3 "; 234 | ArrayList list = new ArrayList(); 235 | Cursor c = ExecSQLForCursor(sql); 236 | while (c.moveToNext()) { 237 | OrderBean info = new OrderBean(); 238 | info.setMoney(c.getString(c.getColumnIndex("money"))); 239 | info.setMark(c.getString(c.getColumnIndex("mark"))); 240 | info.setType(c.getString(c.getColumnIndex("type"))); 241 | info.setNo(c.getString(c.getColumnIndex("tradeno"))); 242 | info.setDt(c.getString(c.getColumnIndex("dt"))); 243 | info.setResult(c.getString(c.getColumnIndex("result"))); 244 | info.setTime(c.getInt(c.getColumnIndex("time"))); 245 | list.add(info); 246 | } 247 | c.close(); 248 | return list; 249 | } 250 | 251 | /** 252 | * 执行SQL,返回一个游标 253 | * 254 | * @param sql 255 | * @return 256 | */ 257 | private Cursor ExecSQLForCursor(String sql) { 258 | Cursor c = db.rawQuery(sql, null); 259 | return c; 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/ExecutorManager.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import android.os.AsyncTask; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | 7 | import java.util.concurrent.Executor; 8 | 9 | import static android.os.AsyncTask.THREAD_POOL_EXECUTOR; 10 | 11 | 12 | public class ExecutorManager { 13 | private static Executor mParallelExecutor = THREAD_POOL_EXECUTOR; 14 | private static Executor mSerialExecutor = AsyncTask.SERIAL_EXECUTOR; 15 | private static Handler sHandler = new Handler(Looper.getMainLooper()); 16 | 17 | private ExecutorManager() { 18 | mParallelExecutor = THREAD_POOL_EXECUTOR; 19 | mSerialExecutor = AsyncTask.SERIAL_EXECUTOR; 20 | } 21 | 22 | public static void runOnUIThread(Runnable runnable) { 23 | sHandler.post(runnable); 24 | } 25 | 26 | public static void executeTask(Runnable task) { 27 | executeTask(task, true); 28 | } 29 | 30 | public static void executeTaskSerially(Runnable task) { 31 | executeTask(task, false); 32 | } 33 | 34 | public static void executeTask(Runnable task, boolean parallel) { 35 | if (parallel) { 36 | mParallelExecutor.execute(task); 37 | return; 38 | } 39 | mSerialExecutor.execute(task); 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/JsonHelper.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | 4 | import java.lang.reflect.Type; 5 | 6 | import com.google.myjson.Gson; 7 | import com.google.myjson.JsonElement; 8 | import com.google.myjson.JsonObject; 9 | 10 | /** 11 | * JsonHelper 12 | * 13 | * @author wrbug 14 | * @since 2017/9/29 15 | */ 16 | public class JsonHelper { 17 | private static Gson sGson = new Gson(); 18 | 19 | public static String toJson(Object o) { 20 | if (o == null) { 21 | return ""; 22 | } 23 | return sGson.toJson(o); 24 | } 25 | 26 | 27 | public static JsonObject fromJson(Object json) { 28 | return fromJson(json, JsonObject.class); 29 | } 30 | 31 | public static T fromJson(Object json, Class tClass) { 32 | try { 33 | 34 | if (json == null) { 35 | return null; 36 | } 37 | if (json instanceof JsonElement) { 38 | return sGson.fromJson((JsonElement) json, tClass); 39 | } 40 | return sGson.fromJson(json.toString(), tClass); 41 | } catch (Throwable t) { 42 | 43 | } 44 | return null; 45 | } 46 | 47 | public static T fromJson(Object json, Type tClass) { 48 | try { 49 | if (json == null) { 50 | return null; 51 | } 52 | if (json instanceof JsonElement) { 53 | return sGson.fromJson((JsonElement) json, tClass); 54 | } 55 | return sGson.fromJson(json.toString(), tClass); 56 | 57 | } catch (Throwable t) { 58 | 59 | } 60 | return null; 61 | } 62 | 63 | public static Gson getGson() { 64 | return sGson; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/LauncherLimitUtils.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | 4 | import com.tools.payhelper.BuildConfig; 5 | 6 | public class LauncherLimitUtils { 7 | 8 | public static void checkLauncherLimit(int dayAfter) { 9 | long limitTimestamp = TimeUtils.getTimeStampByTimeString(BuildConfig.BUILD_TIME, "yyyy-MM-dd") 10 | + dayAfter * TimeUtils.MILLISECONDS_PER_DAY; 11 | if (System.currentTimeMillis() > limitTimestamp) { 12 | throw new RuntimeException("The apk is invalid."); 13 | } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/LogToFile.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.OutputStreamWriter; 9 | import java.text.SimpleDateFormat; 10 | import java.util.Date; 11 | import java.util.Locale; 12 | 13 | import android.content.Context; 14 | import android.os.Environment; 15 | 16 | /** 17 | * Created by admin on 2018/3/26. 18 | */ 19 | 20 | public class LogToFile { 21 | 22 | private static String TAG = "LogToFile"; 23 | 24 | private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);//日期格式; 25 | private static SimpleDateFormat dateFormat_log = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);//日期格式; 26 | 27 | /** 28 | * 获得文件存储路径 29 | * 30 | * @return 31 | */ 32 | public static String getFilePath() { 33 | String logPath = null; 34 | logPath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/PayHelper/logs";//获得文件储存路径,在后面加"/Logs"建立子文件夹 35 | File file = new File(logPath); 36 | if (file.exists()) { 37 | if (getFolderSize(file) > 150 * 1024 * 1024) { 38 | deleteFile(file); 39 | } 40 | } else { 41 | file.mkdirs(); 42 | } 43 | return logPath; 44 | } 45 | 46 | private static final char VERBOSE = 'v'; 47 | 48 | private static final char DEBUG = 'd'; 49 | 50 | private static final char INFO = 'i'; 51 | 52 | private static final char WARN = 'w'; 53 | 54 | private static final char ERROR = 'e'; 55 | 56 | public static void v(String tag, String msg) { 57 | writeToFile(VERBOSE, tag, msg); 58 | } 59 | 60 | public static void d(String tag, String msg) { 61 | File file = new File(getFilePath()); 62 | if (getFolderSize(file) < 500 * 1024 * 1024) { 63 | writeToFile(DEBUG, tag, msg); 64 | } 65 | 66 | } 67 | 68 | public static void i(String tag, String msg) { 69 | writeToFile(INFO, tag, msg); 70 | } 71 | 72 | public static void w(String tag, String msg) { 73 | writeToFile(WARN, tag, msg); 74 | } 75 | 76 | public static void e(String tag, String msg) { 77 | writeToFile(ERROR, tag, msg); 78 | } 79 | 80 | /** 81 | * 将log信息写入文件中 82 | * 83 | * @param type 84 | * @param tag 85 | * @param msg 86 | */ 87 | private static void writeToFile(char type, String tag, String msg) { 88 | 89 | String fileName = getFilePath() + "/log_" + dateFormat.format(new Date()) + ".txt";//log日志名,使用时间命名,保证不重复 90 | String log = dateFormat_log.format(new Date()) + " " + type + " " + tag + " " + msg + "\n";//log日志内容,可以自行定制 91 | 92 | //如果父路径不存在 93 | File file = new File(getFilePath()); 94 | if (!file.exists()) { 95 | file.mkdirs();//创建父路径 96 | } 97 | 98 | FileOutputStream fos = null;//FileOutputStream会自动调用底层的close()方法,不用关闭 99 | BufferedWriter bw = null; 100 | try { 101 | 102 | fos = new FileOutputStream(fileName, true);//这里的第二个参数代表追加还是覆盖,true为追加,flase为覆盖 103 | bw = new BufferedWriter(new OutputStreamWriter(fos)); 104 | bw.write(log); 105 | 106 | } catch (FileNotFoundException e) { 107 | e.printStackTrace(); 108 | } catch (IOException e) { 109 | e.printStackTrace(); 110 | } finally { 111 | try { 112 | if (bw != null) { 113 | bw.close();//关闭缓冲流 114 | } 115 | } catch (IOException e) { 116 | e.printStackTrace(); 117 | } 118 | } 119 | 120 | } 121 | 122 | public static long getFolderSize(File file) { 123 | 124 | long size = 0; 125 | try { 126 | File[] fileList = file.listFiles(); 127 | for (int i = 0; i < fileList.length; i++) { 128 | if (fileList[i].isDirectory()) { 129 | size = size + getFolderSize(fileList[i]); 130 | 131 | } else { 132 | size = size + fileList[i].length(); 133 | 134 | } 135 | } 136 | } catch (Exception e) { 137 | // TODO Auto-generated catch block 138 | e.printStackTrace(); 139 | } 140 | return size; 141 | } 142 | 143 | /** 144 | * 删除日志 145 | * 146 | * @param file 147 | */ 148 | public static void deleteFile(File file) { 149 | if (file.isDirectory()) { 150 | File[] files = file.listFiles(); 151 | for (int i = 0; i < files.length; i++) { 152 | File f = files[i]; 153 | deleteFile(f); 154 | } 155 | // file.delete();//如要保留文件夹,只删除文件,请注释这行 156 | } else if (file.exists()) { 157 | file.delete(); 158 | } 159 | } 160 | 161 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Date; 10 | import java.util.Locale; 11 | 12 | 13 | /** 14 | *

15 | * The log tool support write log to file, need the follow permission. 16 | *

"android.permission.WRITE_EXTERNAL_STORAGE"

17 | *

"android.permission.MOUNT_UNMOUNT_FILESYSTEMS"

18 | *

19 | * 20 | * @since Create on 2016/10/31. 21 | **/ 22 | public class LogUtils { 23 | 24 | private static final String TAG = "LogUtils"; 25 | 26 | /** 27 | * Whether output log 28 | */ 29 | private static boolean mDebug = false; 30 | /** 31 | * Whether write log to file 32 | */ 33 | private static boolean mWriteFile; 34 | /** 35 | * The log dir parent path. 36 | */ 37 | private static File mWriteLogDir = null; 38 | /** 39 | * The log dir. 40 | */ 41 | private static final String LOG_FILE_PATH = "log"; 42 | /** 43 | * The format for date. 44 | */ 45 | private static SimpleDateFormat mDateFormat = null; 46 | /** 47 | * The FileOutputStream for write log. 48 | */ 49 | private static FileOutputStream mFileOutputStream = null; 50 | 51 | public static void init(Context context, boolean debug, boolean writeFile) { 52 | mDebug = debug; 53 | mWriteFile = writeFile; 54 | if (mWriteFile) { 55 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 56 | mWriteLogDir = new File(Environment.getExternalStorageDirectory(), context.getPackageName()); 57 | } else { 58 | mWriteLogDir = new File(context.getCacheDir(), context.getPackageName()); 59 | } 60 | mWriteLogDir = new File(mWriteLogDir, LOG_FILE_PATH); 61 | } 62 | } 63 | 64 | public static void d(String msg) { 65 | if (mDebug) { 66 | android.util.Log.d(TAG, buildMessage(msg)); 67 | } 68 | } 69 | 70 | public static void d(String tag, String msg) { 71 | if (mDebug) { 72 | android.util.Log.d(tag, buildMessage(msg)); 73 | } 74 | } 75 | 76 | public static void i(String msg) { 77 | if (mDebug) { 78 | android.util.Log.i(TAG, buildMessage(msg)); 79 | } 80 | } 81 | 82 | public static void i(String tag, String msg) { 83 | if (mDebug) { 84 | android.util.Log.i(tag, buildMessage(msg)); 85 | } 86 | } 87 | 88 | public static void w(String msg) { 89 | if (mDebug) { 90 | android.util.Log.w(TAG, buildMessage(msg)); 91 | } 92 | } 93 | 94 | public static void w(String tag, String msg) { 95 | if (mDebug) { 96 | android.util.Log.w(tag, buildMessage(msg)); 97 | } 98 | } 99 | 100 | public static void e(String msg) { 101 | if (mDebug) { 102 | android.util.Log.e(TAG, buildMessage(msg)); 103 | } 104 | } 105 | 106 | public static void e(String tag, String msg) { 107 | if (mDebug) { 108 | android.util.Log.e(tag, buildMessage(msg)); 109 | } 110 | } 111 | 112 | public static void e(Exception ex) { 113 | if (mDebug && null != ex) { 114 | android.util.Log.e(TAG, buildMessage(ex.toString()), ex); 115 | } 116 | } 117 | 118 | public static void e(String msg, Exception ex) { 119 | if (mDebug && null != ex) { 120 | android.util.Log.e(TAG, buildMessage(msg + ex.toString()), ex); 121 | } 122 | } 123 | 124 | public static void e(String tag, String msg, Exception ex) { 125 | if (mDebug && null != ex) { 126 | android.util.Log.e(tag, buildMessage(msg + ex.toString()), ex); 127 | } 128 | } 129 | 130 | private static String buildMessage(String msg) { 131 | StackTraceElement caller = Thread.currentThread().getStackTrace()[4]; 132 | StringBuilder text = new StringBuilder(); 133 | text.append(caller.getFileName() 134 | .replace(".java", "")) 135 | .append(".") 136 | .append(caller.getMethodName()) 137 | .append("[") 138 | .append(caller.getLineNumber()) 139 | .append("]:") 140 | .append(msg); 141 | if (mWriteFile) { 142 | writeLog2File(text.toString()); 143 | } 144 | return text.toString(); 145 | } 146 | 147 | private static void writeLog2File(String text) { 148 | try { 149 | if (null == mFileOutputStream) { 150 | mDateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SSS", Locale.getDefault()); 151 | File file = new File(mWriteLogDir, "log_" + mDateFormat.format(new Date()) + ".txt"); 152 | if (!file.exists()) { 153 | File parentFile = file.getParentFile(); 154 | if (null != parentFile && !parentFile.exists() && !parentFile.mkdirs()) { 155 | // has parent dir, but make failed. 156 | android.util.Log.e(TAG, "mkdirs is " + false); 157 | return; 158 | } 159 | 160 | if (!file.exists()) { 161 | // has not file 162 | android.util.Log.e(TAG, "has not file."); 163 | if (!file.createNewFile()) { 164 | // has not file, but create failed. 165 | android.util.Log.e(TAG, "createNewFile is " + false); 166 | } 167 | } 168 | } 169 | mFileOutputStream = new FileOutputStream(file, true); 170 | } 171 | String log = mDateFormat.format(new Date()) + ":(" + TAG + ")" + " >> " + text + "\n"; 172 | mFileOutputStream.write(log.getBytes()); 173 | mFileOutputStream.flush(); 174 | } catch (Exception e) { 175 | android.util.Log.e(TAG, "Write error: " + e.toString()); 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/Logger.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by efan on 2017/4/13. 7 | */ 8 | 9 | public class Logger { 10 | 11 | //设为false关闭日志 12 | private static final boolean LOG_ENABLE = true; 13 | 14 | public static void i(String tag, String msg){ 15 | if (LOG_ENABLE){ 16 | Log.i(tag, msg); 17 | } 18 | } 19 | public static void v(String tag, String msg){ 20 | if (LOG_ENABLE){ 21 | Log.v(tag, msg); 22 | } 23 | } 24 | public static void d(String tag, String msg){ 25 | if (LOG_ENABLE){ 26 | Log.d(tag, msg); 27 | } 28 | } 29 | public static void w(String tag, String msg){ 30 | if (LOG_ENABLE){ 31 | Log.w(tag, msg); 32 | } 33 | } 34 | public static void e(String tag, String msg){ 35 | if (LOG_ENABLE){ 36 | Log.e(tag, msg); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/MD5.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.security.MessageDigest; 4 | /** 5 | * 说明:MD5处理 6 | * 创建人:FH Q313596790 7 | * 修改时间:2014年9月20日 8 | * @version 9 | */ 10 | public class MD5 { 11 | 12 | public static String md5(String str) { 13 | try { 14 | MessageDigest md = MessageDigest.getInstance("MD5"); 15 | md.update(str.getBytes()); 16 | byte b[] = md.digest(); 17 | 18 | int i; 19 | 20 | StringBuffer buf = new StringBuffer(""); 21 | for (int offset = 0; offset < b.length; offset++) { 22 | i = b[offset]; 23 | if (i < 0) 24 | i += 256; 25 | if (i < 16) 26 | buf.append("0"); 27 | buf.append(Integer.toHexString(i)); 28 | } 29 | str = buf.toString(); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | 33 | } 34 | return str; 35 | } 36 | 37 | public static String md5byte(byte[] str) { 38 | String str1 = null; 39 | try { 40 | MessageDigest md = MessageDigest.getInstance("MD5"); 41 | md.update(str); 42 | byte b[] = md.digest(); 43 | 44 | int i; 45 | 46 | StringBuffer buf = new StringBuffer(""); 47 | for (int offset = 0; offset < b.length; offset++) { 48 | i = b[offset]; 49 | if (i < 0) 50 | i += 256; 51 | if (i < 16) 52 | buf.append("0"); 53 | buf.append(Integer.toHexString(i)); 54 | } 55 | str1 = buf.toString(); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | 59 | } 60 | return str1; 61 | } 62 | public static void main(String[] args) { 63 | System.out.println(md5("31119@qq.com"+"123456")); 64 | System.out.println(md5("mj1")); 65 | System.out.println(md5("1BQljr6O6WxeHGZ77JU2qQ1eiMQvBdFFl3xTYWEIfW4=")); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/OrderBean.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 7 | 8 | * @ClassName: OrderBean 9 | 10 | * @Description: TODO(这里用一句话描述这个类的作用) 11 | 12 | * @author SuXiaoliang 13 | 14 | * @date 2018年6月23日 下午1:27:27 15 | 16 | * 17 | */ 18 | public class OrderBean implements Serializable{ 19 | private static final long serialVersionUID = 8988815091574805671L; 20 | private String money; 21 | private String mark; 22 | private String type; 23 | private String no; 24 | private String dt; 25 | private String result; 26 | private int time; 27 | 28 | 29 | public OrderBean() { 30 | super(); 31 | } 32 | public OrderBean(String money, String mark, String type, String no, String dt, String result, int time) { 33 | super(); 34 | this.money = money; 35 | this.mark = mark; 36 | this.type = type; 37 | this.no = no; 38 | this.dt = dt; 39 | this.result = result; 40 | this.time = time; 41 | } 42 | public String getMoney() { 43 | return money; 44 | } 45 | public void setMoney(String money) { 46 | this.money = money; 47 | } 48 | public String getMark() { 49 | return mark; 50 | } 51 | public void setMark(String mark) { 52 | this.mark = mark; 53 | } 54 | public String getType() { 55 | return type; 56 | } 57 | public void setType(String type) { 58 | this.type = type; 59 | } 60 | public String getNo() { 61 | return no; 62 | } 63 | public void setNo(String no) { 64 | this.no = no; 65 | } 66 | public String getDt() { 67 | return dt; 68 | } 69 | public void setDt(String dt) { 70 | this.dt = dt; 71 | } 72 | public String getResult() { 73 | return result; 74 | } 75 | public void setResult(String result) { 76 | this.result = result; 77 | } 78 | public int getTime() { 79 | return time; 80 | } 81 | public void setTime(int time) { 82 | this.time = time; 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/QQDBHelper.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteOpenHelper; 6 | 7 | /** 8 | * 9 | 10 | * @ClassName: QQDBHelper 11 | 12 | * @Description: TODO(这里用一句话描述这个类的作用) 13 | 14 | * @author SuXiaoliang 15 | 16 | * @date 2018年6月23日 下午1:27:36 17 | 18 | * 19 | */ 20 | public class QQDBHelper extends SQLiteOpenHelper{ 21 | public QQDBHelper(Context context) { 22 | super(context, "mark.db", null, 1); 23 | } 24 | 25 | @Override 26 | public void onCreate(SQLiteDatabase db) { 27 | db.execSQL("CREATE TABLE IF NOT EXISTS mark" + 28 | "(_id INTEGER PRIMARY KEY AUTOINCREMENT, money varchar, mark varchar, status varchar, dt varchar)"); 29 | } 30 | 31 | @Override 32 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 33 | // TODO Auto-generated method stub 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/QQDBManager.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.util.ArrayList; 4 | 5 | import android.content.Context; 6 | import android.database.Cursor; 7 | import android.database.sqlite.SQLiteDatabase; 8 | 9 | /** 10 | * 11 | 12 | * @ClassName: QQDBManager 13 | 14 | * @Description: TODO(这里用一句话描述这个类的作用) 15 | 16 | * @author SuXiaoliang 17 | 18 | * @date 2018年6月23日 下午1:27:40 19 | 20 | * 21 | */ 22 | public class QQDBManager { 23 | private SQLiteDatabase db; 24 | private QQDBHelper helper; 25 | public QQDBManager(Context context){ 26 | helper = new QQDBHelper(context); 27 | db = helper.getWritableDatabase(); 28 | } 29 | 30 | public void addQQMark(String money,String mark) { 31 | db.beginTransaction();// 开始事务 32 | try { 33 | String dt=System.currentTimeMillis()+""; 34 | db.execSQL("INSERT INTO mark VALUES(null,?,?,?,?)", new Object[] { money, mark, "0", dt}); 35 | db.setTransactionSuccessful();// 事务成功 36 | } finally { 37 | db.endTransaction();// 结束事务 38 | } 39 | } 40 | public void updateOrder(String money,String mark) { 41 | db.beginTransaction();// 开始事务 42 | try { 43 | db.execSQL("UPDATE mark SET status='1' WHERE money=? and mark=?", new Object[] {money, mark}); 44 | db.setTransactionSuccessful();// 事务成功 45 | } finally { 46 | db.endTransaction();// 结束事务 47 | } 48 | } 49 | 50 | public ArrayList FindQQMark(String money,String mark) { 51 | String sql = "SELECT * FROM mark WHERE money='"+money+"' and mark='"+mark+"' and status='0'"; 52 | ArrayList list = new ArrayList(); 53 | Cursor c = ExecSQLForCursor(sql); 54 | while (c.moveToNext()) { 55 | QrCodeBean info = new QrCodeBean(); 56 | info.setMoney(c.getString(c.getColumnIndex("money"))); 57 | info.setMark(c.getString(c.getColumnIndex("mark"))); 58 | info.setDt(c.getString(c.getColumnIndex("dt"))); 59 | list.add(info); 60 | } 61 | c.close(); 62 | return list; 63 | } 64 | public QrCodeBean GetQQMark() { 65 | String sql = "SELECT * FROM mark WHERE status='0' order by dt desc"; 66 | Cursor c = ExecSQLForCursor(sql); 67 | QrCodeBean info = new QrCodeBean(); 68 | if (c.moveToNext()) { 69 | info.setMoney(c.getString(c.getColumnIndex("money"))); 70 | info.setMark(c.getString(c.getColumnIndex("mark"))); 71 | info.setDt(c.getString(c.getColumnIndex("dt"))); 72 | } 73 | c.close(); 74 | return info; 75 | } 76 | 77 | /** 78 | * 执行SQL,返回一个游标 79 | * 80 | * @param sql 81 | * @return 82 | */ 83 | private Cursor ExecSQLForCursor(String sql) { 84 | Cursor c = db.rawQuery(sql, null); 85 | return c; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/QRUtils.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.util.Hashtable; 4 | 5 | import com.google.zxing.BinaryBitmap; 6 | import com.google.zxing.ChecksumException; 7 | import com.google.zxing.DecodeHintType; 8 | import com.google.zxing.FormatException; 9 | import com.google.zxing.NotFoundException; 10 | import com.google.zxing.RGBLuminanceSource; 11 | import com.google.zxing.Result; 12 | import com.google.zxing.common.HybridBinarizer; 13 | import com.google.zxing.qrcode.QRCodeReader; 14 | 15 | import android.graphics.Bitmap; 16 | import android.graphics.BitmapFactory; 17 | import android.text.TextUtils; 18 | 19 | public class QRUtils { 20 | 21 | /** 22 | * 解析二维码图片 23 | * @param path 24 | * @return 25 | */ 26 | public static Result scanningImage(String path) { 27 | Bitmap scanBitmap; 28 | if (TextUtils.isEmpty(path)) { 29 | return null; 30 | 31 | } 32 | Hashtable hints = new Hashtable(); 33 | hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); // 设置二维码内容的编码 34 | BitmapFactory.Options options = new BitmapFactory.Options(); 35 | options.inJustDecodeBounds = true; // 先获取原大小 36 | // scanBitmap = BitmapFactory.decodeFile(path,options); 37 | scanBitmap=ImageUtils.getBitmapByFile(path); 38 | options.inJustDecodeBounds = false; 39 | int sampleSize = (int) (options.outHeight / (float) 200); 40 | if (sampleSize <= 0) { 41 | sampleSize = 1; 42 | } 43 | 44 | options.inSampleSize = sampleSize; 45 | 46 | scanBitmap = BitmapFactory.decodeFile(path, options); 47 | int[] data = new int[scanBitmap.getWidth() * scanBitmap.getHeight()]; 48 | scanBitmap.getPixels(data, 0, scanBitmap.getWidth(), 0, 0, scanBitmap.getWidth(), scanBitmap.getHeight()); 49 | RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(scanBitmap.getWidth(),scanBitmap.getHeight(),data); 50 | BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(rgbLuminanceSource)); 51 | QRCodeReader reader = new QRCodeReader(); 52 | Result result = null; 53 | try { 54 | result = reader.decode(binaryBitmap, hints); 55 | } catch (NotFoundException e) { 56 | LogUtils.e("NotFoundException"); 57 | }catch (ChecksumException e){ 58 | LogUtils.e("ChecksumException"); 59 | } catch (FormatException e) { 60 | // TODO Auto-generated catch block 61 | e.printStackTrace(); 62 | } 63 | 64 | return result; 65 | 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/QrCodeBean.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.io.Serializable; 4 | import java.text.DecimalFormat; 5 | 6 | /** 7 | * 8 | 9 | * @ClassName: QrCodeBean 10 | 11 | * @Description: TODO(这里用一句话描述这个类的作用) 12 | 13 | * @author SuXiaoliang 14 | 15 | * @date 2018年6月23日 下午1:27:45 16 | 17 | * 18 | */ 19 | public class QrCodeBean implements Serializable{ 20 | private static final long serialVersionUID = 8988815091574805671L; 21 | private static final String serialVersionSTR = "1BQljr6O6WxeHGZ77JU2qQ1eiMQvBdFFl3xTYWEIfW4="; 22 | 23 | private String money; 24 | private String mark; 25 | private String type; 26 | private String payurl; 27 | private String dt; 28 | 29 | 30 | public QrCodeBean(String money, String mark, String type, String payurl, String dt) { 31 | super(); 32 | this.money = money; 33 | this.mark = mark; 34 | this.type = type; 35 | this.payurl = payurl; 36 | this.dt = dt; 37 | } 38 | 39 | public QrCodeBean() { 40 | super(); 41 | } 42 | 43 | public String getMoney() { 44 | return money; 45 | } 46 | 47 | public void setMoney(String money) { 48 | this.money = money; 49 | } 50 | 51 | public String getMark() { 52 | return mark; 53 | } 54 | 55 | public void setMark(String mark) { 56 | this.mark = mark; 57 | } 58 | 59 | public String getType() { 60 | return type; 61 | } 62 | 63 | public void setType(String type) { 64 | this.type = type; 65 | } 66 | 67 | public String getPayurl() { 68 | return payurl; 69 | } 70 | 71 | public void setPayurl(String payurl) { 72 | this.payurl = payurl; 73 | } 74 | 75 | public String getDt() { 76 | return dt; 77 | } 78 | 79 | public void setDt(String dt) { 80 | this.dt = dt; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | 11 | import android.content.Context; 12 | import android.telephony.TelephonyManager; 13 | 14 | public class StringUtils { 15 | 16 | public static void main(String[] args) { 17 | } 18 | 19 | public static byte[] getBytes(String filePath) { 20 | byte[] buffer = null; 21 | try { 22 | File file = new File(filePath); 23 | FileInputStream fis = new FileInputStream(file); 24 | ByteArrayOutputStream bos = new ByteArrayOutputStream(1000); 25 | byte[] b = new byte[1000]; 26 | int n; 27 | while ((n = fis.read(b)) != -1) { 28 | bos.write(b, 0, n); 29 | } 30 | fis.close(); 31 | bos.close(); 32 | buffer = bos.toByteArray(); 33 | } catch (FileNotFoundException e) { 34 | e.printStackTrace(); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | return buffer; 39 | } 40 | 41 | public static void getFile(byte[] bfile, String filePath, String fileName) { 42 | BufferedOutputStream bos = null; 43 | FileOutputStream fos = null; 44 | File file = null; 45 | try { 46 | File dir = new File(filePath); 47 | if (!dir.exists() && !dir.isDirectory()) {// �ж��ļ�Ŀ¼�Ƿ����? 48 | dir.mkdirs(); 49 | } 50 | file = new File(filePath + "\\" + fileName); 51 | fos = new FileOutputStream(file); 52 | bos = new BufferedOutputStream(fos); 53 | bos.write(bfile); 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } finally { 57 | if (bos != null) { 58 | try { 59 | bos.close(); 60 | } catch (IOException e1) { 61 | e1.printStackTrace(); 62 | } 63 | } 64 | if (fos != null) { 65 | try { 66 | fos.close(); 67 | } catch (IOException e1) { 68 | e1.printStackTrace(); 69 | } 70 | } 71 | } 72 | } 73 | 74 | public static String getimei(Context context){ 75 | TelephonyManager tm = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE); 76 | String imei=tm.getDeviceId(); 77 | if(imei==null){ 78 | return "00000000000000000"; 79 | }else{ 80 | return tm.getDeviceId(); 81 | } 82 | } 83 | public static String getTextCenter(String text,String begin,String end){ 84 | try { 85 | int b=text.indexOf(begin)+begin.length(); 86 | int e=text.indexOf(end,b); 87 | return text.substring(b,e); 88 | } catch (Exception e) { 89 | // TODO Auto-generated catch block 90 | e.printStackTrace(); 91 | return "error"; 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/Tag.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | 6 | public class Tag { 7 | 8 | private String mPath; 9 | private String mName; 10 | private ArrayList mChildren = new ArrayList<>(); 11 | private String mContent; 12 | 13 | Tag(String path, String name) { 14 | mPath = path; 15 | mName = name; 16 | } 17 | 18 | void addChild(Tag tag) { 19 | mChildren.add(tag); 20 | } 21 | 22 | String getName() { 23 | return mName; 24 | } 25 | 26 | String getContent() { 27 | return mContent; 28 | } 29 | 30 | void setContent(String content) { 31 | boolean hasContent = false; 32 | if (content != null) { 33 | for (int i = 0; i < content.length(); ++i) { 34 | char c = content.charAt(i); 35 | if ((c != ' ') && (c != '\n')) { 36 | hasContent = true; 37 | break; 38 | } 39 | } 40 | } 41 | if (hasContent) { 42 | mContent = content; 43 | } 44 | } 45 | 46 | ArrayList getChildren() { 47 | return mChildren; 48 | } 49 | 50 | boolean hasChildren() { 51 | return (mChildren.size() > 0); 52 | } 53 | 54 | int getChildrenCount() { 55 | return mChildren.size(); 56 | } 57 | 58 | Tag getChild(int index) { 59 | if ((index >= 0) && (index < mChildren.size())) { 60 | return mChildren.get(index); 61 | } 62 | return null; 63 | } 64 | 65 | HashMap> getGroupedElements() { 66 | HashMap> groups = new HashMap<>(); 67 | for (Tag child : mChildren) { 68 | String key = child.getName(); 69 | ArrayList group = groups.get(key); 70 | if (group == null) { 71 | group = new ArrayList<>(); 72 | groups.put(key, group); 73 | } 74 | group.add(child); 75 | } 76 | return groups; 77 | } 78 | 79 | String getPath() { 80 | return mPath; 81 | } 82 | 83 | @Override 84 | public String toString() { 85 | return "Tag: " + mName + ", " + mChildren.size() + " children, Content: " + mContent; 86 | } 87 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tools/payhelper/utils/TimeUtils.java: -------------------------------------------------------------------------------- 1 | package com.tools.payhelper.utils; 2 | 3 | import android.annotation.SuppressLint; 4 | 5 | import java.text.DecimalFormat; 6 | import java.text.ParseException; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Calendar; 9 | import java.util.Date; 10 | import java.util.TimeZone; 11 | 12 | 13 | public class TimeUtils { 14 | 15 | /** 16 | * The milliseconds in one second 17 | */ 18 | public static final int MILLISECONDS_PER_SECOND = 1000; 19 | /** 20 | * The second in one minute 21 | */ 22 | public static final int SECOND_PER_MINUTE = 60; 23 | /** 24 | * The minute in one hour 25 | */ 26 | public static final int MINUTE_PER_HOUR = 60; 27 | /** 28 | * The second in one hour 29 | */ 30 | public static final int SECOND_PER_HOUR = 3600; 31 | /** 32 | * The hour in one day 33 | */ 34 | public static final int HOUR_PER_DAY = 24; 35 | /** 36 | * The minute in one day 37 | */ 38 | public static final int MINUTE_PER_DAY = 1440; 39 | /** 40 | * The second in one day 41 | */ 42 | public static final int SECOND_PER_DAY = 86400; 43 | /** 44 | * The milliseconds in one day 45 | */ 46 | public static final int MILLISECONDS_PER_DAY = 86400000; 47 | /** 48 | * The day in one week 49 | */ 50 | public static final int DAY_PRE_WEEK = 7; 51 | /** 52 | * The month in one year 53 | */ 54 | public static final int MONTH_PRE_YEAR = 12; 55 | 56 | /** 57 | * Get the time zone. 58 | * 59 | * @return the time zone. 60 | */ 61 | public int getTimeZone() { 62 | Calendar cal = Calendar.getInstance(); 63 | int zoneOffset = cal.get(Calendar.ZONE_OFFSET); 64 | int dstOffset = cal.get(Calendar.DST_OFFSET); 65 | return ((zoneOffset + dstOffset) / MILLISECONDS_PER_SECOND) / (MINUTE_PER_HOUR * SECOND_PER_MINUTE); 66 | } 67 | 68 | /** 69 | * Get the offset of time zone. 70 | * 71 | * @return the offset of time zone. 72 | */ 73 | public int getTimeZoneOffset() { 74 | return TimeZone.getDefault().getOffset(System.currentTimeMillis()) / 1000; 75 | } 76 | 77 | /** 78 | * Get the day count of month. 79 | * 80 | * @param year year 81 | * @param month month 1-12 82 | * @return the day count of month. 83 | */ 84 | public int getMonthDays(int year, int month) { 85 | Calendar calendar = Calendar.getInstance(); 86 | calendar.set(year, month - 1, 1); 87 | return calendar.getActualMaximum(Calendar.DAY_OF_MONTH); 88 | } 89 | 90 | /** 91 | * Get the value of field. 92 | * 93 | * @param field Calendar.YEAR 94 | * @return the value of field 95 | */ 96 | public int getCalendarField(int field) { 97 | Calendar calendar = Calendar.getInstance(); 98 | return calendar.get(field); 99 | } 100 | 101 | /** 102 | * Get the local timestamp(second) 103 | * 104 | * @return second 105 | */ 106 | public int getLocalSecond() { 107 | return (int) (System.currentTimeMillis() / 1000 + getTimeZoneOffset()); 108 | } 109 | 110 | /** 111 | * Get the utc timestamp(second) 112 | * 113 | * @return second 114 | */ 115 | public static int getUtcSecond() { 116 | return (int) (System.currentTimeMillis() / 1000); 117 | } 118 | 119 | /** 120 | * Get the utc timestamp(milliseconds) 121 | * 122 | * @return milliseconds 123 | */ 124 | public static long getUtcMilliseconds() { 125 | return System.currentTimeMillis(); 126 | } 127 | 128 | /** 129 | * Get the local timestamp(milliseconds) 130 | * 131 | * @return milliseconds 132 | */ 133 | public int getLocalMilliseconds() { 134 | return (int) (System.currentTimeMillis() / 1000 + getTimeZoneOffset()); 135 | } 136 | 137 | /** 138 | * Get the time string by timestamp(second) 139 | * 140 | * @param time the timestamp 141 | * @param format the format string like yyyy-MM-dd 142 | * @return the time string like 2016-12-17 143 | */ 144 | public static String formatTime(int time, String format) { 145 | return formatTime(time * 1000L, format); 146 | } 147 | 148 | /** 149 | * Get the time sting by timestamp(milliseconds) 150 | * 151 | * @param time the timestamp 152 | * @param format the format string like yyyy-MM-dd 153 | * @return the time string like 2016-12-17 154 | */ 155 | @SuppressLint("SimpleDateFormat") 156 | public static String formatTime(Long time, String format) { 157 | SimpleDateFormat sdf = new SimpleDateFormat(format); 158 | return sdf.format(new Date(time)); 159 | } 160 | 161 | /** 162 | * Get the timestamp by time string 163 | * 164 | * @param timeStr the time string like 2016-12-17 165 | * @param format the format string like yyyy-MM-dd 166 | * @return the timestamp 167 | */ 168 | @SuppressLint("SimpleDateFormat") 169 | public static long getTimeStampByTimeString(String timeStr, String format) { 170 | long time = 0; 171 | SimpleDateFormat sdf = new SimpleDateFormat(format); 172 | try { 173 | Date d = sdf.parse(timeStr); 174 | time = d.getTime(); 175 | } catch (ParseException e) { 176 | e.printStackTrace(); 177 | } 178 | return time; 179 | } 180 | 181 | /** 182 | * get the time stamp by time string 183 | * 184 | * @param time the time string like 2016-12-17 185 | * @param format the format string like yyyy-MM-dd 186 | * @return milliseconds 187 | */ 188 | @SuppressLint("SimpleDateFormat") 189 | public static long getMillisSecond(String time, String format) { 190 | SimpleDateFormat sdf = new SimpleDateFormat(format); 191 | try { 192 | return sdf.parse(time).getTime(); 193 | } catch (ParseException e) { 194 | e.printStackTrace(); 195 | } 196 | return 0L; 197 | } 198 | 199 | /** 200 | * Second time convert to String like(12:45:30) 201 | * 202 | * @param totalSeconds the total second time 203 | * @return the string like 12:45:30 or 45:30 204 | */ 205 | public static String second2TimeString(int totalSeconds) { 206 | DecimalFormat df = new DecimalFormat("00"); 207 | StringBuilder sb = new StringBuilder(); 208 | int hours = totalSeconds / SECOND_PER_HOUR; 209 | int minutes = (totalSeconds / SECOND_PER_MINUTE) % MINUTE_PER_HOUR; 210 | int seconds = totalSeconds % SECOND_PER_MINUTE; 211 | if (0 < hours) { 212 | sb.append(df.format(hours)).append(":"); 213 | } 214 | sb.append(df.format(minutes)).append(":").append(df.format(seconds)); 215 | return sb.toString(); 216 | } 217 | 218 | /** 219 | * Second time convert to String like(02.03'04") 220 | * 221 | * @param totalSeconds the total second time 222 | * @return the string like 02.03'04" or 03'04" 223 | */ 224 | public static String second2TimeString1(int totalSeconds) { 225 | DecimalFormat df = new DecimalFormat("00"); 226 | StringBuilder sb = new StringBuilder(); 227 | int hours = totalSeconds / SECOND_PER_HOUR; 228 | int minutes = (totalSeconds / SECOND_PER_MINUTE) % MINUTE_PER_HOUR; 229 | int seconds = totalSeconds % SECOND_PER_MINUTE; 230 | if (0 < hours) { 231 | sb.append(df.format(hours)).append("."); 232 | } 233 | sb.append(df.format(minutes)).append("\'").append(df.format(seconds)).append("\""); 234 | return sb.toString(); 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/btn_back_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/src/main/res/drawable-hdpi/btn_back_grey.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/src/main/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhinoSp/PayHelper6.6.7_NewAPI/ca6ee805234fd7613ad9263c91c4f6da78ea90e5/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 |