左晓为主开发手持机充值管理机
da8f72d2db0bbfc221a881d5aa31065cd5717043..c1e964b330bf9ebff290ce993a55328ec63a8ab3
2024-02-26 zuoxiao
开启修改密码
c1e964 对比 | 目录
2024-02-22 zuoxiao
读卡时检验设备是否注册
dc1ab1 对比 | 目录
2024-01-09 zuoxiao
修改权限框架 添加包名和签名验证 数据库文件隐藏
0baf94 对比 | 目录
11个文件已修改
237 ■■■■■ 已修改文件
app/build.gradle 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/androidTest/java/com/dayu/recharge/ExampleInstrumentedTest.java 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/BaseActivity.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/HomeActivity.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/LoginActivity.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/NewCardActivity.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/ReadCardAcitivy.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/dao/BaseDaoSingleton.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/tools/BaseNFCHelper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
settings.gradle 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/build.gradle
@@ -16,14 +16,14 @@
        applicationId "com.dayu.recharge"
        minSdk 23
        targetSdk 26
        versionCode 1
        versionName "1.0"
        versionCode 14
        versionName "1.4"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        ndk{
            abiFilters 'armeabi-v7a'
        }
//        ndk{
//            abiFilters 'armeabi-v7a'
//        }
        signingConfig signingConfigs.debug
    }
@@ -79,12 +79,8 @@
    implementation 'com.tencent.bugly:crashreport:latest.release'
//    处理图片
//    implementation (name: 'ocr-library', ext: 'aar')
    //权限
    implementation ('com.guolindev.permissionx:permissionx:1.7.1'){
        exclude group: 'androidx.core';
        exclude group: 'androidx.appcompat';
        exclude group: 'androidx.annotation';
    }
    //权限申请
    implementation 'com.github.getActivity:XXPermissions:18.5'
    //滚动选择框
    implementation 'com.contrarywind:Android-PickerView:4.1.9'
app/src/androidTest/java/com/dayu/recharge/ExampleInstrumentedTest.java
@@ -2,25 +2,25 @@
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
//import androidx.test.platform.app.InstrumentationRegistry;
//import androidx.test.ext.junit.runners.AndroidJUnit4;
//
//import org.junit.Test;
//import org.junit.runner.RunWith;
//
//import static org.junit.Assert.*;
/**
 * Instrumented test, which will execute on an Android device.
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void useAppContext() {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
        assertEquals("com.dayu.recharge", appContext.getPackageName());
    }
}
//@RunWith(AndroidJUnit4.class)
//public class ExampleInstrumentedTest {
//    @Test
//    public void useAppContext() {
//        // Context of the app under test.
//        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
//        assertEquals("com.dayu.recharge", appContext.getPackageName());
//    }
//}
app/src/main/java/com/dayu/recharge/activity/BaseActivity.java
@@ -1,11 +1,17 @@
package com.dayu.recharge.activity;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.dayu.recharge.MyApplication;
import com.dayu.recharge.R;
import com.dayu.recharge.dao.AppDatabase;
import com.dayu.recharge.dao.BaseDaoSingleton;
@@ -16,18 +22,25 @@
 */
public class BaseActivity extends AppCompatActivity {
    private final String TAG = "BaseActivity";
    public TitleBar titleBar = null;
    //z主线程查询
    public AppDatabase baseDao;
    //异步线程查询
    public AppDatabase asynchBaseDao;
    public final String SIGN = "308202b8308201a0020101300d06092a864886f70d01010b05003022310f300d06035504030c06e5a4a7e7a6b9310f300d06035504070c06e5a4a9e6b4a5301e170d3233313132303035333131325a170d3438313131333035333131325a3022310f300d06035504030c06e5a4a7e7a6b9310f300d06035504070c06e5a4a9e6b4a530820122300d06092a864886f70d01010105000382010f003082010a0282010100a0924f3d618e4a622def691e16e54ce5bdfd035bd73e7cb947d2bf3bd0c00afa26e52963e0299fc06d76d153be696c5285d630577e1dcb2b740a72b6d904482217de308fb91c8435441ed05e844ced1e5c3446d82cb8f38751049df26a42adcfc33f1f12c2ce03f676e5d148aad800ace89670b87835e2c02a8570a0b6740d9c0669d4cb3c597d0b2dd49fc0904e885773b6d3a87d9f1e73eb526e0d1a9e9e3c48d986938286cd824151b5a6214faf89d3e699524511b23c86d3b110a7f0bb56a6d2436f69816538a62a38cb1fee6eb685d267cc200df8af51b936bd280beaa2023f75678d77a11ac6de734b30af63d394c8b63bccf2115a47ea15c9212c740d0203010001300d06092a864886f70d01010b05000382010100307cafa9b14be91ba6424cfcc6aed75b069a1c4d6eb646eab0de93f372f236f5f0a6097499df99391075d6ced18d419a2b15adb041890e2b56a3bfbd6be40efee99c5c713ba8ea1d45da09b67916106116e96eb735271c4d53e0739f753145cbc42e149ad3d9507d422ec1c6f1a7f792a4542f9a64f0de3d4f4af69f0fb3390ef3577dcf8844cf744426d173b0934d879148062c5ca64022dc99af370dbfeaf2b5d4a279b20c54a361bca12c25bf185c2885519bbbc36e46ddb083080f0cc5b1f2eafe964ebce5071b0ae7d92a34a9193861b996d2c0299b1993f41063a27038199365a6e3cb27a02ffa9facdc48a63713eb5fbf90e9fd73056aba16b28e5fee";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        baseDao = BaseDaoSingleton.getInstance(this);
        asynchBaseDao = BaseDaoSingleton.getAsynchInstance(this);
        Log.i(TAG, SIGN);
        if (!isMyApp()) {
            Log.i(TAG, "isMyApp");
            this.finish();
        }
    }
@@ -52,5 +65,24 @@
        }
    }
    public boolean isMyApp() {
        String signStr = getSign();
        return SIGN.equals(signStr);
    }
    public String getSign() {
        try {
            PackageInfo packageInfo = this.getPackageManager().getPackageInfo(this.getPackageName(), PackageManager.GET_SIGNATURES);
            Signature[] signatures = packageInfo.signatures;
            StringBuilder builder = new StringBuilder();
            for (Signature signature : signatures) {
                builder.append(signature.toCharsString());
            }
            return builder.toString();
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return "";
    }
}
app/src/main/java/com/dayu/recharge/activity/HomeActivity.java
@@ -1,6 +1,5 @@
package com.dayu.recharge.activity;
import android.Manifest;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
@@ -13,8 +12,6 @@
import com.dayu.recharge.databinding.ActivityHomeBinding;
import com.dayu.recharge.dbBean.AdminDataBean;
import com.dayu.recharge.utils.TipUtil;
import com.dayu.recharge.utils.ToastUtil;
import com.permissionx.guolindev.PermissionX;
/**
app/src/main/java/com/dayu/recharge/activity/LoginActivity.java
@@ -8,6 +8,7 @@
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.dayu.recharge.MyApplication;
@@ -15,10 +16,12 @@
import com.dayu.recharge.databinding.ActivityLoginBinding;
import com.dayu.recharge.dbBean.PassWordBean;
import com.dayu.recharge.utils.TipUtil;
import com.dayu.recharge.utils.WSMD5;
import com.permissionx.guolindev.PermissionX;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;
import java.io.File;
import java.util.List;
/**
@@ -27,7 +30,7 @@
 * Date: 2023-11-10 19:52
 * Description: 登录界面
 */
public class LoginActivity extends AppCompatActivity {
public class LoginActivity extends BaseActivity {
    ActivityLoginBinding binding;
    PassWordBean passWordBean;
@@ -62,27 +65,51 @@
    }
    private void getPermission() {
        PermissionX.init(LoginActivity.this).permissions(Manifest.permission.READ_PHONE_STATE,
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .onExplainRequestReason((scope, deniedList) -> {
                })
                .request((allGranted, grantedList, deniedList) -> {
                    if (allGranted) {//所有申请的权限都已通过
                        MyApplication.myApplication.initEasySocket(false, null);
                        try {
                            File file = new File(BaseDaoSingleton.SqlitePath);
                            if (!file.exists()) {
                                file.mkdirs();
        try {
            XXPermissions.with(this)
                    // 申请单个权限
//                    .permission(Permission.RECORD_AUDIO)
                    // 申请多个权限
                    .permission(Permission.READ_PHONE_STATE,
                            Permission.READ_EXTERNAL_STORAGE,
                            Permission.WRITE_EXTERNAL_STORAGE)
                    // 设置权限请求拦截器(局部设置)
                    //.interceptor(new PermissionInterceptor())
                    // 设置不触发错误检测机制(局部设置)
                    //.unchecked()
                    .request(new OnPermissionCallback() {
                        @Override
                        public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                            if (allGranted) {
                                if (allGranted) {//所有申请的权限都已通过
                                    MyApplication.myApplication.initEasySocket(false, null);
                                    try {
                                        File file = new File(BaseDaoSingleton.SqlitePath);
                                        if (!file.exists()) {
                                            file.mkdirs();
                                        }
                                        passWordBean = BaseDaoSingleton.getInstance(LoginActivity.this).loginPsDao().findFirst();
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                            passWordBean = BaseDaoSingleton.getInstance(this).loginPsDao().findFirst();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else {//您拒绝了如下权限:$deniedList
                    }
                });
                        @Override
                        public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                            if (doNotAskAgain) {
                                // 如果是被永久拒绝就跳转到应用权限系统设置页面
                            } else {
//                                toast("获取录音和日历权限失败");
                            }
                        }
                    });
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}
app/src/main/java/com/dayu/recharge/activity/NewCardActivity.java
@@ -1,6 +1,5 @@
package com.dayu.recharge.activity;
import android.Manifest;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
@@ -10,8 +9,7 @@
import android.view.LayoutInflater;
import android.view.View;
import com.dayu.recharge.utils.DeviceNumberUtils;
import com.dayu.recharge.view.ProgressDialog;
import androidx.annotation.NonNull;
import com.dayu.recharge.MyApplication;
import com.dayu.recharge.card.UserCard;
@@ -28,14 +26,19 @@
import com.dayu.recharge.tools.HexUtil;
import com.dayu.recharge.tools.Utils;
import com.dayu.recharge.utils.CRC8;
import com.dayu.recharge.utils.DeviceNumberUtils;
import com.dayu.recharge.utils.SocketUtil;
import com.dayu.recharge.utils.TipUtil;
import com.permissionx.guolindev.PermissionX;
import com.dayu.recharge.view.ProgressDialog;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -75,7 +78,7 @@
            @Override
            public void onClick(View v) {
                rxPermission();
                getPermission();
            }
        });
@@ -154,22 +157,40 @@
    }
    private void rxPermission() {
        PermissionX.init(NewCardActivity.this).permissions(Manifest.permission.CAMERA)
                .onExplainRequestReason((scope, deniedList) -> {
    private void getPermission() {
        try {
            XXPermissions.with(this)
                    // 申请单个权限
//                    .permission(Permission.RECORD_AUDIO)
                    // 申请多个权限
                    .permission(Permission.CAMERA)
                    // 设置权限请求拦截器(局部设置)
                    //.interceptor(new PermissionInterceptor())
                    // 设置不触发错误检测机制(局部设置)
                    //.unchecked()
                    .request(new OnPermissionCallback() {
// val message = "PermissionX需要您同意以下权限才能正常使用"
                })
                .request((allGranted, grantedList, deniedList) -> {
                    if (allGranted) {//所有申请的权限都已通过
//                        startCamera();
                    } else {//您拒绝了如下权限:$deniedList
                        @Override
                        public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                            if (allGranted) {
                            }
                        }
                    }
                });
                        @Override
                        public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                            if (doNotAskAgain) {
                                // 如果是被永久拒绝就跳转到应用权限系统设置页面
                            } else {
//                                toast("获取录音和日历权限失败");
                            }
                        }
                    });
        } catch (
                Throwable e) {
            e.printStackTrace();
        }
    }
    @Override
@@ -349,6 +370,7 @@
            // 汉字的Unicode范围是:0x4e00 - 0x9fa5
            return (c >= 0x4e00 && c <= 0x9fa5);
        }
    }
    @Override
app/src/main/java/com/dayu/recharge/activity/ReadCardAcitivy.java
@@ -3,6 +3,7 @@
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -216,10 +217,14 @@
     * @param initPeasantCode 农户注册编号
     */
    private void selectBalance(String initPeasantCode) {
        String initCode = DeviceNumberUtils.getDeviceNumber();
        if (TextUtils.isEmpty(initCode)) {
            TipUtil.show("设备未注册");
            return;
        }
        BalanceSelecteRequestBean requestBean = new BalanceSelecteRequestBean();
        requestBean.setAFN("94");
        requestBean.setControl("01");
        String initCode = DeviceNumberUtils.getDeviceNumber();
        requestBean.setInitCode(initCode);
        requestBean.setInitPeasantCode(initPeasantCode);
        requestBean.setXuLie(SocketUtil.getXuLie(this));
@@ -282,7 +287,6 @@
                TipUtil.show(ReadCardAcitivy.this, msg);
            }
        });
    }
}
app/src/main/java/com/dayu/recharge/dao/BaseDaoSingleton.java
@@ -19,7 +19,7 @@
public class BaseDaoSingleton {
    public static AppDatabase baseDao;
    public static AppDatabase AsynchBaseDao;
    public static String SqlitePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dayu" + File.separator + "data" + File.separator;
    public static String SqlitePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + ".dayu" + File.separator + "data" + File.separator;
    //MyFileUtil.SqlitePath +
    public static AppDatabase getInstance(Context context) {
app/src/main/java/com/dayu/recharge/tools/BaseNFCHelper.java
@@ -58,14 +58,15 @@
//             byte[] encryptedBytes2 = Base64.decode("aYC9feYEOFOQHuzflLIXSw==", Base64.DEFAULT);
            byte[] encryptedBytes2 = Base64.decode("qeg4DUWf0ni9JfRWtD2krA==", Base64.DEFAULT);
            byte[] decryptedBytes2 = cipher.doFinal(encryptedBytes2);
            //decryptedBytes2 对应010203040506
            companyKeyA = new String(decryptedBytes2, StandardCharsets.UTF_8);
            companyKey = HexUtil.hexToByteArray(companyKeyA);
            //修改后的密码
            byte[] encryptedBytes3 = Base64.decode("n+SSZFb4DHsreVav/Z5ftg==", Base64.DEFAULT);
            byte[] decryptedBytes3 = cipher.doFinal(encryptedBytes3);
            companyKeyB = new String(decryptedBytes3, StandardCharsets.UTF_8);
            //decryptedBytes3 对应202311202048
            companyKeyB = new String(decryptedBytes2, StandardCharsets.UTF_8);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java
@@ -66,7 +66,7 @@
    public boolean writeData(byte[] str, int a, int b) {
        Log.i("NFCWreatActivity", "writeData: a=" + a + " b=" + b);
        //写卡时修改所有密码
//        changePasword(a);
        changePasword(a);
        if (str.length <= 16) {
            try {
                MifareClassic mfc = MifareClassic.get(tag);
@@ -142,7 +142,7 @@
                        data[i] = dataA[i];
                    }
                    //输入控制位
                    data[6] = (byte) 0xff;
                    data[6] = (byte) 0xFF;
                    data[7] = (byte) 0x07;
                    data[8] = (byte) 0x80;
                    data[9] = (byte) 0x69;
@@ -155,6 +155,11 @@
                    int bCount = mfc.getBlockCountInSector(a);
                    //写到扇区的最后一个块
                    mfc.writeBlock(bIndex + bCount - 1, data);
//                    byte[] dataa = mfc.readBlock(bIndex + bCount - 1);
//                    // 修改密码 A
//                    mfc.writeBlock(mfc.sectorToBlock(a) + 3, dataA);
//                    // 修改密码 B
//                    mfc.writeBlock(mfc.sectorToBlock(a) + 7, dataB);
                }
                return true;
            } catch (Exception e) {
settings.gradle
@@ -11,6 +11,7 @@
        google()
        jcenter()
        mavenCentral()
        maven {url 'https://www.jitpack.io'}
    }
}
rootProject.name = "Recharge"