左晓为主开发手持机充值管理机
zuojincheng
2025-03-26 1bc1acff2127d61b359800096ad5b904370d9176
refactor(nfc): 重构 NFC 读写助手类

-移除了 HuaZhiNfcReadHelper 类
- 更新了 BaseNfcReadHelper 和 BaseNfcWriteHelper 接口
-重构了 NativeNfcReadHelper 和 NativeNfcWriteHelper 类
- 更新了 NfcReadAdapter 和 NfcWriteAdapter 类
-调整了 ModelUtils 类中的 getModelType 方法
25个文件已修改
1个文件已删除
2个文件已添加
1066 ■■■■ 已修改文件
app/build.gradle 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/activity/BaseNfcActivity.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcReadHelper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcWriteHelper.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/HuaZhiNfcReadHepler.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcWriteHelper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcReadAdapter.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcWriteAdapter.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/utils/ModelUtils.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
build.gradle 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/AndroidManifest.xml 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/cpp/general-native-lib.cpp 305 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/ManageListActivity.kt 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/ManagerReadActivity.kt 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt 105 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/BaseCard.kt 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/UserCard.kt 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/tool/GeBaseHelper.kt 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/tool/NfcWreatHelper.kt 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/activity_manager_read.xml 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
henanlibrary/src/main/java/com/dayu/henanlibrary/tools/NFCWriteHelper.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
henanlibrary/src/main/java/com/dayu/henanlibrary/tools/NfcReadHelper.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
qihealonelibrary/src/main/java/com/dayu/qihealonelibrary/tools/NFCWriteHelper.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
qihealonelibrary/src/main/java/com/dayu/qihealonelibrary/tools/NfcReadHelper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
qiheonlinelibrary/src/main/java/com/dayu/qiheonlinelibrary/tools/NFCWriteHelper.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
qiheonlinelibrary/src/main/java/com/dayu/qiheonlinelibrary/tools/NfcReadHelper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/build.gradle
@@ -3,7 +3,7 @@
android {
    signingConfigs {
        debug {
            storeFile file('../dycz.jks')
            storeFile file(myValue)
            storePassword 'dycz@2023'
            keyAlias 'dayu'
            keyPassword 'dycz@2023'
baselibrary/src/main/java/com/dayu/baselibrary/activity/BaseNfcActivity.java
@@ -6,11 +6,8 @@
import android.nfc.NfcAdapter;
import android.os.Bundle;
import com.dayu.baselibrary.tools.nfc.HuaZhiNfcReadHepler;
import com.dayu.baselibrary.utils.ModelUtils;
import com.dayu.baselibrary.utils.TipUtil;
import com.pos.device.picc.PiccReader;
import com.pos.device.picc.PiccReaderCallback;
/**
 * author: zuo
@@ -51,23 +48,6 @@
            case ModelUtils.defaultType:
            case ModelUtils.ShangMiType:
                adapterType = ModelUtils.defaultType;
                break;
            case ModelUtils.HuaZhiRongHaiType:
                adapterType = ModelUtils.HuaZhiRongHaiType;
                PiccReader.getInstance().startSearchCard(HuaZhiNfcReadHepler.TIMEOUT, new PiccReaderCallback() {
                    @Override
                    public void onSearchResult(int result, int cardType) {
                        if (result == PiccReaderCallback.SUCCESS) {
                            switch (cardType) {
                                //以下为M1卡
                                case PiccReader.MIFARE_ONE_S50:
                                case PiccReader.MIFARE_ONE_S70:
                                    onNfcBack(null);
                                    break;
                            }
                        }
                    }
                });
                break;
        }
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcReadHelper.java
@@ -1,5 +1,7 @@
package com.dayu.baselibrary.tools.nfc;
import android.content.Intent;
import com.dayu.baselibrary.bean.BaseManagerToUserCard;
import com.dayu.baselibrary.bean.BaseUserCardCard;
@@ -15,6 +17,8 @@
public abstract class BaseNfcReadHelper extends BaseNFCHelper {
    public abstract void setIntent(Intent intent);
    public abstract String getCradType();
    /**
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcWriteHelper.java
@@ -1,5 +1,6 @@
package com.dayu.baselibrary.tools.nfc;
import android.content.Intent;
import android.nfc.tech.MifareClassic;
import com.dayu.baselibrary.bean.BaseUserCardCard;
@@ -11,13 +12,16 @@
 * 备注:
 */
public abstract class BaseNfcWriteHelper extends BaseNFCHelper {
    public abstract void setIntent(Intent intent);
    /**
     * 写卡
     *
     * @param userCard 用户卡内容
     * @param
     * @param sector   书写的扇区 (从0开始数)
     */
    public abstract boolean writeUserData(BaseUserCardCard userCard);
    public abstract boolean writeUserData(BaseUserCardCard userCard,int sector);
    /**
     * 写卡
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/HuaZhiNfcReadHepler.java
File was deleted
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java
@@ -32,8 +32,14 @@
    public NativeNfcReadHelper(Intent intent, Activity activity) {
    }
    @Override
    public void setIntent(Intent intent) {
        this.tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    }
    /**
     * 单例初始化
@@ -45,6 +51,7 @@
        if (helper == null) {
            helper = new NativeNfcReadHelper(intent, activity);
        }
        helper.setIntent(intent);
        return helper;
    }
@@ -55,7 +62,7 @@
     */
    @Override
    public BaseUserCardCard getUserCardData(BaseUserCardCard userCardCard) {
        if (userCardCard!=null){
        if (userCardCard != null) {
            BaseUserCardCard userCard = null;
            Map<String, List<byte[]>> map = new HashMap<>();
            MifareClassic mfc = MifareClassic.get(tag);
@@ -117,6 +124,7 @@
        }
        return null;
    }
    @Override
    public String getCradType() {
@@ -386,15 +394,15 @@
                mfc.connect();
                //获取当前卡号
                boolean isOpen = false;
                if (!listKeyA.isEmpty()){
                if (!listKeyA.isEmpty()) {
                    for (int i = 0; i < listKeyA.size(); i++) {
                        if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) {
                            isOpen = true;
                            break;
                        }
                    }
                }else if (!listA_PS.isEmpty()){
                    if (mfc.authenticateSectorWithKeyA(0,   listA_PS.get(0))){
                } else if (!listA_PS.isEmpty()) {
                    if (mfc.authenticateSectorWithKeyA(0, listA_PS.get(0))) {
                        isOpen = true;
                    }
                }
@@ -424,6 +432,47 @@
        return "";
    }
    public String getCardNumberNoClose() {
        MifareClassic mfc = MifareClassic.get(tag);
        if (null != mfc) {
            try {
                mfc.connect();
                //获取当前卡号
                boolean isOpen = false;
                if (!listKeyA.isEmpty()) {
                    for (int i = 0; i < listKeyA.size(); i++) {
                        if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) {
                            isOpen = true;
                            break;
                        }
                    }
                } else if (!listA_PS.isEmpty()) {
                    if (mfc.authenticateSectorWithKeyA(0, listA_PS.get(0))) {
                        isOpen = true;
                    }
                }
                if (isOpen) {
                    int bIndex = mfc.sectorToBlock(0);
                    byte[] data = mfc.readBlock(bIndex + 0);
                    if (data != null && data.length > 0) {
                        String hex = HexUtil.bytesToHex(Arrays.copyOfRange(data, 0, 4));
                        hex = HexUtil.spaceHex(hex);
                        hex = HexUtil.HighLowHex(hex);
                        Log.i("NFCWreatActivity", "hex===" + hex);
                        return hex.toUpperCase();
                    }
                }
            } catch (IOException e) {
                Log.i("NFCWreatActivity", e.toString());
                return BaseCommon.CARD_TYPE_ERROR1;
            }
        }
        return "";
    }
    /**
     * 获取卡片类型和卡号
     *
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcWriteHelper.java
@@ -24,6 +24,9 @@
    private static NativeNfcWriteHelper helper;
    public NativeNfcWriteHelper(Intent intent, Activity activity) {
    }
    public void setIntent(Intent intent) {
        this.tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    }
@@ -37,6 +40,7 @@
        if (helper == null) {
            helper = new NativeNfcWriteHelper(intent, activity);
        }
        helper.setIntent(intent);
        return helper;
    }
@@ -48,9 +52,9 @@
     * @param
     */
    @Override
    public boolean writeUserData(BaseUserCardCard userCard) {
    public boolean writeUserData(BaseUserCardCard userCard, int sector) {
        if (userCard != null) {
            int a = 1;
            int a = sector;
            try {
                MifareClassic mfc = MifareClassic.get(tag);
                if (null != mfc) {
@@ -122,7 +126,7 @@
    @Override
    public boolean writeData(byte[] str, int a, int b, NFCCallBack callBack) {
        Log.i("NFCWreatActivity", "writeData: a=" + a + " b=" + b);
        if (str.length <= 16) {
        if (str.length == 16) {
            try {
                MifareClassic mfc = MifareClassic.get(tag);
                if (null != mfc) {
@@ -169,8 +173,6 @@
                                }
                            }
                        }
                        if (isOpen) {
                            int bIndex = mfc.sectorToBlock(a);
                            //写卡
@@ -225,8 +227,11 @@
                }
            } catch (Exception e) {
                e.printStackTrace();
                callBack.isSusses(false, a + "扇区写卡报错" + e.getMessage());
                return false;
            }
        } else {
            callBack.isSusses(false, a + "扇区写卡报错,byte数组大小不为16");
        }
        return false;
    }
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcReadAdapter.java
@@ -19,6 +19,11 @@
    NativeNfcReadHelper nativeNfcReadHelper;
    @Override
    public void setIntent(Intent intent) {
        nativeNfcReadHelper.setIntent(intent);
    }
    public NfcReadAdapter(Intent intent, Activity activity) {
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
@@ -63,12 +68,20 @@
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
                return nativeNfcReadHelper.getCardNumber();
        }
        return "";
    }
    public String getCardNumberNoClose() {
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
                return nativeNfcReadHelper.getCardNumberNoClose();
        }
        return "";
    }
    @Override
    public String getCradTypeAndCardNumber() {
        switch (BaseNfcActivity.adapterType) {
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcWriteAdapter.java
@@ -26,10 +26,15 @@
    }
    @Override
    public boolean writeUserData(BaseUserCardCard userCard) {
    public void setIntent(Intent intent) {
        nativeNfcWriteHelper.setIntent(intent);
    }
    @Override
    public boolean writeUserData(BaseUserCardCard userCard,int sector) {
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
                return nativeNfcWriteHelper.writeUserData(userCard);
                return nativeNfcWriteHelper.writeUserData(userCard, sector);
        }
        return false;
baselibrary/src/main/java/com/dayu/baselibrary/utils/ModelUtils.java
@@ -22,13 +22,13 @@
    //判断是哪个机型
    public static int getModelType() {
        int type;
        try {
            Class.forName("com.pos.device.config.DevConfig");
            type = ModelUtils.HuaZhiRongHaiType;
            return type;
        } catch (ClassNotFoundException e) {
//        try {
//            Class.forName("com.pos.device.config.DevConfig");
//            type = ModelUtils.HuaZhiRongHaiType;
//            return type;
//        } catch (ClassNotFoundException e) {
            type = ModelUtils.ShangMiType;
            return type;
        }
//        }
    }
}
build.gradle
@@ -8,4 +8,8 @@
    id 'com.android.application' version '7.2.2' apply false
    id 'com.android.library' version '7.2.2' apply false
    id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
}
ext {
    myValue = 'C:\\Users\\User\\StudioProjects\\charge\\dycz.jks'
}
generallibrary/src/main/AndroidManifest.xml
@@ -50,12 +50,27 @@
        <activity android:name="com.dayu.general.activity.NewCardActivity" />
        <activity android:name="com.dayu.general.activity.ManageListActivity" />
        <activity android:name="com.dayu.general.activity.SearchUserActivity"/>
        <activity android:name="com.dayu.general.activity.NfcWreatActivity" />
        <activity android:name="com.dayu.general.activity.NfcWreatActivity"
            android:exported="false"
            android:launchMode="singleTop"
            >
            <intent-filter>
                <action android:name="android.nfc.action.ACTION_NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
        </activity>
        <activity android:name=".activity.MainActivity"/>
        <activity
            android:name=".activity.ManagerReadActivity"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustResize"/>
            android:exported="false"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.nfc.action.ACTION_NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
        </activity>
generallibrary/src/main/cpp/general-native-lib.cpp
@@ -3,66 +3,134 @@
#include <android/log.h>
#include <string.h>
#include <jni.h>
#include <sstream>
#include <iomanip>
static jclass contextClass;
static jclass signatureClass;
static jclass packageNameClass;
static jclass packageInfoClass;
// 声明全局静态变量,用于存储Java类的引用
static jclass contextClass;      // Android Context类的引用
static jclass signatureClass;    // Android Signature类的引用
static jclass packageNameClass;  // Android PackageManager类的引用
static jclass packageInfoClass;  // Android PackageInfo类的引用
// 定义发布版本的签名常量
const char *RELEASE_SIGN = "308202b8308201a0020101300d06092a864886f70d01010b05003022310f300d06035504030c06e5a4a7e7a6b9310f300d06035504070c06e5a4a9e6b4a5301e170d3233313132303035333131325a170d3438313131333035333131325a3022310f300d06035504030c06e5a4a7e7a6b9310f300d06035504070c06e5a4a9e6b4a530820122300d06092a864886f70d01010105000382010f003082010a0282010100a0924f3d618e4a622def691e16e54ce5bdfd035bd73e7cb947d2bf3bd0c00afa26e52963e0299fc06d76d153be696c5285d630577e1dcb2b740a72b6d904482217de308fb91c8435441ed05e844ced1e5c3446d82cb8f38751049df26a42adcfc33f1f12c2ce03f676e5d148aad800ace89670b87835e2c02a8570a0b6740d9c0669d4cb3c597d0b2dd49fc0904e885773b6d3a87d9f1e73eb526e0d1a9e9e3c48d986938286cd824151b5a6214faf89d3e699524511b23c86d3b110a7f0bb56a6d2436f69816538a62a38cb1fee6eb685d267cc200df8af51b936bd280beaa2023f75678d77a11ac6de734b30af63d394c8b63bccf2115a47ea15c9212c740d0203010001300d06092a864886f70d01010b05000382010100307cafa9b14be91ba6424cfcc6aed75b069a1c4d6eb646eab0de93f372f236f5f0a6097499df99391075d6ced18d419a2b15adb041890e2b56a3bfbd6be40efee99c5c713ba8ea1d45da09b67916106116e96eb735271c4d53e0739f753145cbc42e149ad3d9507d422ec1c6f1a7f792a4542f9a64f0de3d4f4af69f0fb3390ef3577dcf8844cf744426d173b0934d879148062c5ca64022dc99af370dbfeaf2b5d4a279b20c54a361bca12c25bf185c2885519bbbc36e46ddb083080f0cc5b1f2eafe964ebce5071b0ae7d92a34a9193861b996d2c0299b1993f41063a27038199365a6e3cb27a02ffa9facdc48a63713eb5fbf90e9fd73056aba16b28e5fee";
// 定义XOR加密密钥数组
const unsigned char XOR_KEY[] = {0x7A, 0xB3, 0xC9, 0x7B, 0xE3, 0x78};  // 修改后三个字节的密钥
// 加密密钥
const unsigned char XOR_KEY[] = {0x7A, 0xB3, 0xC9, 0xD5, 0xE1, 0xF8, 0x42, 0x91, 0x37, 0x8F, 0x5D,
                                 0x2E};
// 定义后半部分XOR密钥数组
const unsigned char XOR_KEY_BACK[] = {0x4D, 0xE4, 0x7C, 0x2A, 0x8B, 0x7F};
// 加密后的M1卡密码数组
// 定义加密后的M1卡扇区密钥数组
const unsigned char ENCRYPTED_SECTOR_KEYS[] = {
        // 扇区0密码 (加密后)
        0x9C, 0x45, 0x36, 0x55, 0x8C, 0x7F, 0x35, 0x93, 0x4B, 0x78, 0x2A, 0x79,
        // 扇区1密码 (加密后)
        0xB4, 0x52, 0x91, 0x45, 0x99, 0x87, 0x3C, 0xA3, 0x6E, 0x5F, 0x1D, 0x5E,
        // 以下类似格式存储其他扇区密码...
        0x1E, 0x85, 0xEB, 0x51, 0xB9, 0x39, 0x02, 0x2E, 0x77, 0x1F, 0x3E, 0x93,
        0x22, 0x62, 0xBD, 0x83, 0x99, 0x2A, 0x2F, 0x19, 0x95, 0x07, 0x29, 0x2E,
        0x90, 0x18, 0xE0, 0x6A, 0xB7, 0x68, 0x34, 0x89, 0x42, 0x5B, 0x16, 0x47,
        0xA8, 0x0B, 0xB5, 0x97, 0xB4, 0x43, 0x1D, 0x62, 0x89, 0x73, 0x33, 0x2E,
        0x24, 0x9D, 0xB7, 0x46, 0x8D, 0x64, 0x49, 0x7A, 0x52, 0x41, 0x1C, 0x91,
        0x31, 0x78, 0x95, 0x52, 0x95, 0x39, 0x19, 0x4C, 0x81, 0x2A, 0x0D, 0x47,
        0xF5, 0x64, 0xA7, 0x93, 0xB9, 0x51, 0x27, 0x82, 0x43, 0x68, 0x31, 0x3F,
        0x55, 0x93, 0xB7, 0x68, 0x97, 0x9A, 0x37, 0x71, 0x52, 0x49, 0x17, 0x1E,
        0x8E, 0x93, 0xB5, 0x44, 0x8D, 0x42, 0x22, 0x84, 0x95, 0x33, 0x22, 0x93,
        0x42, 0x82, 0xA3, 0x35, 0x91, 0x33, 0x13, 0x93, 0x71, 0x21, 0x01, 0x71,
        0x37, 0x9F, 0xA6, 0x68, 0x92, 0x86, 0x46, 0x72, 0x43, 0x62, 0x12, 0x52,
        0x5D, 0x85, 0x93, 0x86, 0x82, 0x46, 0x31, 0x86, 0x57, 0x48, 0x16, 0x88,
        0x97, 0x73, 0xB5, 0x47, 0x95, 0x55, 0x36, 0x69, 0x49, 0x58, 0x18, 0x6A,
        0xEA, 0x46, 0x84, 0x93, 0x82, 0x19, 0x29, 0x91, 0x31, 0x1C, 0x0C, 0x7D
    // 扇区0密码 (加密后)
    0x9C, 0x45, 0x36, 0x55, 0x8C, 0x7F, 0x35, 0x93, 0x4B, 0x78, 0x2A, 0x79,
    // 扇区1密码 (加密后)
    0xB4, 0x52, 0x91, 0x45, 0x99, 0x87, 0x3C, 0xA3, 0x6E, 0x5F, 0x1D, 0x5E,
    // 以下类似格式存储其他扇区密码...
    0x1E, 0x85, 0xEB, 0x51, 0xB9, 0x39, 0x02, 0x2E, 0x77, 0x1F, 0x3E, 0x93,
    0x22, 0x62, 0xBD, 0x83, 0x99, 0x2A, 0x2F, 0x19, 0x95, 0x07, 0x29, 0x2E,
    0x90, 0x18, 0xE0, 0x6A, 0xB7, 0x68, 0x34, 0x89, 0x42, 0x5B, 0x16, 0x47,
    0xA8, 0x0B, 0xB5, 0x97, 0xB4, 0x43, 0x1D, 0x62, 0x89, 0x73, 0x33, 0x2E,
    0x24, 0x9D, 0xB7, 0x46, 0x8D, 0x64, 0x49, 0x7A, 0x52, 0x41, 0x1C, 0x91,
    0x31, 0x78, 0x95, 0x52, 0x95, 0x39, 0x19, 0x4C, 0x81, 0x2A, 0x0D, 0x47,
    0xF5, 0x64, 0xA7, 0x93, 0xB9, 0x51, 0x27, 0x82, 0x43, 0x68, 0x31, 0x3F,
    0x55, 0x93, 0xB7, 0x68, 0x97, 0x9A, 0x37, 0x71, 0x52, 0x49, 0x17, 0x1E,
    0x8E, 0x93, 0xB5, 0x44, 0x8D, 0x42, 0x22, 0x84, 0x95, 0x33, 0x22, 0x93,
    0x42, 0x82, 0xA3, 0x35, 0x91, 0x33, 0x13, 0x93, 0x71, 0x21, 0x01, 0x71,
    0x37, 0x9F, 0xA6, 0x68, 0x92, 0x86, 0x46, 0x72, 0x43, 0x62, 0x12, 0x52,
    0x5D, 0x85, 0x93, 0x86, 0x82, 0x46, 0x31, 0x86, 0x57, 0x48, 0x16, 0x88,
    0x97, 0x73, 0xB5, 0x47, 0x95, 0x55, 0x36, 0x69, 0x49, 0x58, 0x18, 0x6A,
    0xEA, 0x46, 0x84, 0x93, 0x82, 0x19, 0x29, 0x91, 0x31, 0x1C, 0x0C, 0x7D
};
// 解密函数
void decrypt_key(const unsigned char *encrypted, char *decrypted, size_t len) {
// 将字节数组转换为十六进制字符串的函数
std::string bytesToHexString(const unsigned char* data, size_t len) {
    std::stringstream ss;  // 创建字符串流对象
    ss << std::hex << std::uppercase << std::setfill('0');  // 设置输出格式为十六进制,大写,不足两位补0
    for (size_t i = 0; i < len; i++) {
        decrypted[i] = encrypted[i] ^ XOR_KEY[i % sizeof(XOR_KEY)];
        ss << std::setw(2) << static_cast<int>(data[i]);  // 将每个字节转换为两位十六进制
    }
    decrypted[len] = '\0';
    return ss.str();  // 返回转换后的字符串
}
//extern "C" JNIEXPORT jstring
//
//JNICALL
//Java_com_yglx_testjni_MainActivity_getKey(
//        JNIEnv *env,
//        jobject /* this */) {
//    return env->NewStringUTF(AUTH_KEY);
//}
// 解密函数:使用XOR密钥解密数据
jstring decrypt_key(JNIEnv* env, const unsigned char* encrypted_data, int length) {
    if (!encrypted_data || length < 6) {
        __android_log_print(ANDROID_LOG_ERROR, "GeBaseHelper", "Invalid input data");
        return nullptr;
    }
    // 为不同扇区使用不同的XOR密钥
    const unsigned char XOR_KEYS[16][6] = {
        {0x7A, 0xB3, 0xC9, 0x72, 0xFC, 0x78},  // 扇区0
        {0x7A, 0xB3, 0xC9, 0x5A, 0x05, 0xB7},  // 扇区1
        {0x7A, 0xB3, 0x63, 0x10, 0xF9, 0xA4},  // 扇区2
        {0x7A, 0x73, 0x35, 0xD1, 0xFE, 0x71},  // 扇区3 - 修改第3个字节
        {0x2A, 0x93, 0xF8, 0x13, 0xB1, 0x31},  // 扇区4
        {0x7A, 0xB3, 0x79, 0x6D, 0x40, 0x18},  // 扇区5
        {0x7A, 0xB1, 0x19, 0xDA, 0xD6, 0x9A},  // 扇区6
        {0x7A, 0x13, 0xDD, 0x63, 0x3E, 0x63},  // 扇区7
        {0x7A, 0x73, 0x71, 0x5D, 0x89, 0x11},  // 扇区8
        {0x7A, 0x73, 0xF1, 0xE2, 0xFF, 0xB1},  // 扇区9
        {0x7A, 0x6D, 0xE9, 0x42, 0xBE, 0xA0},  // 扇区10
        {0x7A, 0x43, 0xB1, 0x78, 0x76, 0x3D},  // 扇区11
        {0x79, 0x43, 0xD1, 0xD1, 0x70, 0xEB},  // 扇区12
        {0x7A, 0xB3, 0xBF, 0x49, 0x6B, 0xB1},  // 扇区13
        {0x2B, 0xA3, 0xB3, 0x00, 0x19, 0x2C},  // 扇区14
        {0x7A, 0xF3, 0xDA, 0x8B, 0x98, 0x15}   // 扇区15
    };
    // 获取当前扇区号
    int sector = -1;
    for (int i = 0; i < 16; i++) {
        if (memcmp(encrypted_data, &ENCRYPTED_SECTOR_KEYS[i * 12], 6) == 0) {
            sector = i;
            break;
        }
    }
    if (sector == -1) {
        __android_log_print(ANDROID_LOG_ERROR, "GeBaseHelper", "Unknown sector");
        return nullptr;
    }
//    __android_log_print(ANDROID_LOG_INFO, "GeBaseHelper", "Decrypting sector %d", sector);
//    __android_log_print(ANDROID_LOG_INFO, "GeBaseHelper", "Encrypted data: %02X %02X %02X %02X %02X %02X",
//                       encrypted_data[0], encrypted_data[1], encrypted_data[2],
//                       encrypted_data[3], encrypted_data[4], encrypted_data[5]);
//    __android_log_print(ANDROID_LOG_INFO, "GeBaseHelper", "Using XOR key: %02X %02X %02X %02X %02X %02X",
//                       XOR_KEYS[sector][0], XOR_KEYS[sector][1], XOR_KEYS[sector][2],
//                       XOR_KEYS[sector][3], XOR_KEYS[sector][4], XOR_KEYS[sector][5]);
    unsigned char decrypted[6];
    for (int i = 0; i < 6; i++) {
        decrypted[i] = encrypted_data[i] ^ XOR_KEYS[sector][i];
//        __android_log_print(ANDROID_LOG_INFO, "GeBaseHelper", "Byte %d: %02X ^ %02X = %02X",
//                          i, encrypted_data[i], XOR_KEYS[sector][i], decrypted[i]);
    }
    std::string result;
    result.reserve(13);  // 6 bytes * 2 chars + null terminator
    char hex[3];
    for (int i = 0; i < 6; i++) {
        snprintf(hex, sizeof(hex), "%02X", decrypted[i]);
        result += hex;
    }
//    __android_log_print(ANDROID_LOG_INFO, "GeBaseHelper", "Decrypted result: %s", result.c_str());
    return env->NewStringUTF(result.c_str());
}
// JNI库加载时的初始化函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    jint result = -1;
    JNIEnv *env = NULL;  // 声明JNI环境指针
    jint result = -1;    // 初始化返回值为错误状态
    // 获取JNI环境
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK)
        return result;
    // 获取并保存Java类的全局引用
    contextClass = (jclass) env->NewGlobalRef((env)->FindClass("android/content/Context"));
    signatureClass = (jclass) env->NewGlobalRef((env)->FindClass("android/content/pm/Signature"));
    packageNameClass = (jclass) env->NewGlobalRef(
@@ -70,65 +138,144 @@
    packageInfoClass = (jclass) env->NewGlobalRef(
            (env)->FindClass("android/content/pm/PackageInfo"));
    __android_log_print(ANDROID_LOG_DEBUG, "jw", "sss");
    return JNI_VERSION_1_4;
    __android_log_print(ANDROID_LOG_DEBUG, "M1Card", "JNI_OnLoad completed");  // 输出初始化完成日志
    return JNI_VERSION_1_4;  // 返回JNI版本
}
// 获取M1卡扇区密钥的JNI函数
extern "C"
JNIEXPORT jstring JNICALL
Java_com_dayu_general_tool_GeBaseHelper_getM1SectorKeySecure(JNIEnv *env, jobject instance,
                                                             jobject contextObject,
                                                             jint sectorIndex) {
    // 参数有效性检查
    if (!contextObject || !env) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Invalid parameters");
        return env->NewStringUTF("");
    }
    // 获取包管理器相关方法ID
    jmethodID getPackageManagerId = (env)->GetMethodID(contextClass, "getPackageManager",
                                                       "()Landroid/content/pm/PackageManager;");
    jmethodID getPackageNameId = (env)->GetMethodID(contextClass, "getPackageName",
                                                    "()Ljava/lang/String;");
    jmethodID signToStringId = (env)->GetMethodID(signatureClass, "toCharsString",
                                                  "()Ljava/lang/String;");
    jmethodID getPackageInfoId = (env)->GetMethodID(packageNameClass, "getPackageInfo",
                                                    "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    jmethodID getPackageManagerId = env->GetMethodID(contextClass, "getPackageManager",
                                                   "()Landroid/content/pm/PackageManager;");
    jmethodID getPackageNameId = env->GetMethodID(contextClass, "getPackageName",
                                                "()Ljava/lang/String;");
    jmethodID signToStringId = env->GetMethodID(signatureClass, "toCharsString",
                                              "()Ljava/lang/String;");
    jmethodID getPackageInfoId = env->GetMethodID(packageNameClass, "getPackageInfo",
                                                "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    // 检查方法ID获取是否成功
    if (!getPackageManagerId || !getPackageNameId || !signToStringId || !getPackageInfoId) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to get method IDs");
        return env->NewStringUTF("");
    }
    // 获取应用签名信息
    jobject packageManagerObject = (env)->CallObjectMethod(contextObject, getPackageManagerId);
    jstring packNameString = (jstring) (env)->CallObjectMethod(contextObject, getPackageNameId);
    jobject packageInfoObject = (env)->CallObjectMethod(packageManagerObject, getPackageInfoId,
                                                        packNameString, 64);
    jfieldID signaturefieldID = (env)->GetFieldID(packageInfoClass, "signatures",
                                                  "[Landroid/content/pm/Signature;");
    jobjectArray signatureArray = (jobjectArray) (env)->GetObjectField(packageInfoObject,
                                                                       signaturefieldID);
    jobject signatureObject = (env)->GetObjectArrayElement(signatureArray, 0);
    jobject packageManagerObject = env->CallObjectMethod(contextObject, getPackageManagerId);
    if (!packageManagerObject) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to get PackageManager");
        return env->NewStringUTF("");
    }
    jstring packNameString = (jstring) env->CallObjectMethod(contextObject, getPackageNameId);
    if (!packNameString) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to get package name");
        return env->NewStringUTF("");
    }
    jobject packageInfoObject = env->CallObjectMethod(packageManagerObject, getPackageInfoId,
                                                    packNameString, 64);
    if (!packageInfoObject) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to get PackageInfo");
        return env->NewStringUTF("");
    }
    // 获取签名数组字段ID
    jfieldID signaturefieldID = env->GetFieldID(packageInfoClass, "signatures",
                                              "[Landroid/content/pm/Signature;");
    if (!signaturefieldID) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to get signature field ID");
        return env->NewStringUTF("");
    }
    // 获取签名数组
    jobjectArray signatureArray = (jobjectArray) env->GetObjectField(packageInfoObject,
                                                                   signaturefieldID);
    if (!signatureArray || env->GetArrayLength(signatureArray) == 0) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "No signatures found");
        return env->NewStringUTF("");
    }
    // 获取第一个签名对象
    jobject signatureObject = env->GetObjectArrayElement(signatureArray, 0);
    if (!signatureObject) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to get signature object");
        return env->NewStringUTF("");
    }
    // 获取签名字符串
    const char *signStrng = (env)->GetStringUTFChars(
            (jstring) (env)->CallObjectMethod(signatureObject, signToStringId), 0);
    jstring signatureString = (jstring) env->CallObjectMethod(signatureObject, signToStringId);
    if (!signatureString) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to get signature string");
        return env->NewStringUTF("");
    }
    // 调试日志输出
    __android_log_print(ANDROID_LOG_DEBUG, "M1Card", "Current signature: %s", signStrng);
    // 获取签名字符串的UTF-8字符
    const char *signStrng = env->GetStringUTFChars(signatureString, 0);
    if (!signStrng) {
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to get signature UTF chars");
        return env->NewStringUTF("");
    }
    // 输出当前签名用于调试
//    __android_log_print(ANDROID_LOG_DEBUG, "M1Card", "Current signature: %s", signStrng);
    // 验证签名并返回所有扇区密码
    if (strcmp(signStrng, RELEASE_SIGN) == 0) {
        size_t numKeys = sizeof(ENCRYPTED_SECTOR_KEYS) / 12; // 每个密钥12字节
        char *allKeys = new char[numKeys * 13]; // 为每个密钥预留12个字符+1个分隔符
        allKeys[0] = '\0';
        // 计算密钥数量
        size_t numKeys = sizeof(ENCRYPTED_SECTOR_KEYS) / 12;
        std::string result;
        result.reserve(numKeys * 13);  // 每个密钥12个字符+1个分隔符
        // 解密并转换每个扇区密钥
        for (size_t i = 0; i < numKeys; i++) {
            char decrypted[13];
            decrypt_key(ENCRYPTED_SECTOR_KEYS + (i * 12), decrypted, 12);
            strcat(allKeys, decrypted);
            if (i < numKeys - 1) {
                strcat(allKeys, ",");
//            __android_log_print(ANDROID_LOG_DEBUG, "M1Card", "处理扇区 %zu 的密钥", i);
            // 确保不会越界访问
            if (i * 12 + 6 > sizeof(ENCRYPTED_SECTOR_KEYS)) {
                __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Index out of bounds");
                break;
            }
            // 获取解密后的字符串
            jstring decrypted_str = decrypt_key(env, ENCRYPTED_SECTOR_KEYS + (i * 12), 6);
            if (!decrypted_str) {
//                __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Failed to decrypt key for sector %zu", i);
                continue;
            }
            // 转换成C字符串
            const char* decrypted_chars = env->GetStringUTFChars(decrypted_str, 0);
            if (i > 0) {
                result += ",";  // 添加分隔符
            }
            result += decrypted_chars;  // 使用解密后的数据
            // 释放资源
            env->ReleaseStringUTFChars(decrypted_str, decrypted_chars);
            env->DeleteLocalRef(decrypted_str);
        }
        jstring result = (env)->NewStringUTF(allKeys);
        delete[] allKeys;
        return result;
        // 释放资源并返回结果
        env->ReleaseStringUTFChars(signatureString, signStrng);
        return env->NewStringUTF(result.c_str());
    } else {
        return (env)->NewStringUTF("signature_verification_failed");
        // 签名验证失败
        __android_log_print(ANDROID_LOG_ERROR, "M1Card", "Signature verification failed");
        env->ReleaseStringUTFChars(signatureString, signStrng);
        return env->NewStringUTF("");
    }
}
generallibrary/src/main/java/com/dayu/general/activity/ManageListActivity.kt
@@ -1,8 +1,10 @@
package com.dayu.general.activity
import android.content.Intent
import android.os.Bundle
import com.dayu.baselibrary.view.TitleBar.ClickType_LEFT_IMAGE
import com.dayu.general.databinding.ActivityManageListGeBinding
import com.dayu.general.tool.CardCommon
class ManageListActivity : BaseActivity() {
@@ -16,6 +18,17 @@
    fun initView() {
        binding?.titleBar?.setOnItemclickListner(ClickType_LEFT_IMAGE) { this.finish() }
        binding?.tvCleanCard?.setOnClickListener {
            var intent = Intent(this, ManagerReadActivity::class.java)
            intent.putExtra("cardType", CardCommon.CLEAN_CARD_TYPE)
            startActivity(intent)
        }
        binding?.tvCheckCard?.setOnClickListener {
            var intent = Intent(this, ManagerReadActivity::class.java)
            intent.putExtra("cardType", CardCommon.CHECK_CARD)
            startActivity(intent)
        }
    }
}
generallibrary/src/main/java/com/dayu/general/activity/ManagerReadActivity.kt
New file
@@ -0,0 +1,144 @@
package com.dayu.general.activity
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.databinding.DataBindingUtil
import com.dayu.baselibrary.net.subscribers.SubscriberListener
import com.dayu.baselibrary.utils.BaseCommon
import com.dayu.baselibrary.utils.ToastUtil
import com.dayu.baselibrary.view.TitleBar.ClickType_LEFT_IMAGE
import com.dayu.general.R
import com.dayu.general.databinding.ActivityManagerReadBinding
import com.dayu.general.model.CardInfoModel
import com.dayu.general.net.ApiManager
import com.dayu.general.net.BaseResponse
import com.dayu.general.tool.NfcReadHelper
class ManagerReadActivity : BaseNfcActivity() {
    private lateinit var binding: ActivityManagerReadBinding
    private val viewModel: CardInfoModel = CardInfoModel()
    var cardType = ""
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 初始化数据绑定
        binding = DataBindingUtil.setContentView(this, R.layout.activity_manager_read)
        binding.lifecycleOwner = this
        binding.viewModel = viewModel
        if (intent.hasExtra("cardType")) {
            cardType = intent.getStringExtra("cardType").toString()
        }
        initView()
        initListener()
    }
    private fun initView() {
        binding.titleBar.setCenterText("读卡")
        binding.titleBar.setOnItemclickListner(ClickType_LEFT_IMAGE) { this.finish() }
        binding.btnNext.setOnClickListener {
            if (viewModel.cardNumber.value.isNullOrEmpty()) {
                ToastUtil.show("请先读取卡号")
            } else {
                postCardData(cardType, viewModel.cardNumber.value!!, getRemark())
            }
        }
    }
    private fun initListener() {
        binding.titleBar.setOnItemclickListner(ClickType_LEFT_IMAGE) { finish() }
    }
    /**
     * 设置卡号
     */
    fun setCardNumber(cardNumber: String) {
        viewModel.setCardNumber(cardNumber)
    }
    /**
     * 获取备注信息
     */
    fun getRemark(): String = viewModel.remark.value ?: ""
    override fun onNfcBack(intent: Intent) {
        // 处理NFC读取结果
        NfcReadHelper.getInstance(intent, this).getCardNumber().let { cardNumber ->
            if (cardNumber.isNotEmpty() && !cardNumber.contains(BaseCommon.CARD_TYPE_ERROR2)) {
                binding.btnNext.visibility = View.VISIBLE
                binding.dataLayout.visibility = View.VISIBLE
                binding.rechargeReadLL.visibility = View.GONE
                setCardNumber(cardNumber)
            } else if (cardNumber.contains(BaseCommon.CARD_TYPE_ERROR2)) {
                ToastUtil.show("当前卡密码错误,不是本公司卡")
            }
        }
    }
private fun bytesToHexString(bytes: ByteArray?): String? {
    if (bytes == null || bytes.isEmpty()) return null
    val sb = StringBuilder()
    for (b in bytes) {
        sb.append(String.format("%02X", b))
    }
    return sb.toString()
}
/**
 * 提交数据
 */
fun postCardData(cardType: String, cardAddr: String, remark: String) {
    val map = mutableMapOf<String, Any>()
    if (cardAddr.isNotEmpty()) {
        map["cardAddr"] = cardAddr
    }
    if (cardType.isNotEmpty()) {
//            map["cardType"] = cardType
        map["cardType"] = "5"
    }
    if (remark.isNotEmpty()) {
        map["remarks"] = remark
    }
    // 使用正确的类型参数
    ApiManager.getInstance().requestPostLoading(
        this,
        "/sell/card/create_manager_card",
        String::class.java,
        map,
        object : SubscriberListener<BaseResponse<String>>() {
            override fun onNext(t: BaseResponse<String>) {
                if (t.success) {
                    var intent = Intent(this@ManagerReadActivity, NfcWreatActivity::class.java).apply {
                        putExtra("cardAddr", cardAddr)
                        putExtra("orderId", t.content)
                        putExtra("cardType", cardType)
                    }
                    this@ManagerReadActivity.finish()
                    startActivity(intent)
                } else {
                    // 处理搜索失败的情况
                    ToastUtil.show(t.msg)
                }
            }
            override fun onError(e: Throwable?) {
                super.onError(e)
                ToastUtil.show("搜索失败: ${e?.message ?: "未知错误"}")
            }
        }
    )
}
}
generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt
@@ -1,20 +1,27 @@
package com.dayu.general.activity
    package com.dayu.general.activity
import android.content.Intent
import android.os.Bundle
import com.dayu.baselibrary.net.subscribers.SubscriberListener
import com.dayu.baselibrary.utils.ToastUtil
import com.dayu.general.bean.card.ClearCard
import com.dayu.general.tool.CardCommon
import com.dayu.general.databinding.ActivityNfcWriteGeBinding
import com.dayu.general.net.ApiManager
import com.dayu.general.net.BaseResponse
import com.dayu.general.tool.NfcReadHelper
import com.dayu.general.tool.NfcWreatHelper
/**
 * @author: zuo
 * @date: 2021/3/30
 * @description:写卡界面
 */
class NfcWreatActivity:BaseNfcActivity() {
    var binding:ActivityNfcWriteGeBinding? = null
class NfcWreatActivity : BaseNfcActivity() {
    var binding: ActivityNfcWriteGeBinding? = null
    var cardType = ""
    var orderId = ""
    var cardAddr = ""
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
@@ -26,25 +33,89 @@
    /**
     * 获取数据
     */
    private fun getInitData(){
        cardType= intent?.getStringExtra("cardType")?:""
    private fun getInitData() {
        cardType = intent?.getStringExtra("cardType") ?: ""
        orderId = intent?.getStringExtra("orderId") ?: ""
        cardAddr = intent?.getStringExtra("cardAddr") ?: ""
        if (cardType.isNotEmpty()) {
            when (cardType) {
                CardCommon.CLEAN_CARD_TYPE -> {
                    binding?.cardData?.text = "清零卡写卡"
                }
            }
        }
    }
    private fun setTextData(){
        when(cardType){
            CardCommon.CHECK_CARD->{
                binding?.cardData?.text = "写用户卡"
            }
    override fun onNfcBack(intent: Intent) {
        val nfcReadHelper = NfcReadHelper.getInstance(intent, this)
        val cardNumber = nfcReadHelper.getCardNumberNoClose()
        if (cardNumber.isNotEmpty() && cardNumber == cardAddr) {
            val nfcWreatHelper = NfcWreatHelper.getInstance(intent, this)
            when (cardType) {
                CardCommon.CLEAN_CARD_TYPE -> {
                    var clearCard = ClearCard()
                    nfcWreatHelper.writeData(clearCard.getZeroBytes(), 7, 0) { success, message ->
                        if (success) {
                            postCardData(cardType, cardAddr, "")
                            ToastUtil.show("写卡成功!")
                            // 处理写卡成功的情况
                        } else {
                            // 处理写卡失败的情况
                            ToastUtil.show(message)
                        }
                    }
                }
            }
        } else {
            ToastUtil.show("卡片错误,当前刷的卡与刚刚的卡不一致")
        }
    }
    override fun onNfcBack(intent: Intent?) {
        TODO("Not yet implemented")
        when(cardType){
            CardCommon.CHECK_CARD->{
    fun postCardData(cardType: String, cardAddr: String, remark: String) {
        when (cardType) {
            CardCommon.CHECK_CARD -> {
                binding?.cardData?.text = "写用户卡"
            }
        }
        val map = mutableMapOf<String, Any>()
        if (cardAddr.isNotEmpty()) {
            map["cardAddr"] = cardAddr
        }
        if (cardType.isNotEmpty()) {
//            map["cardType"] = cardType
            map["cardType"] = "5"
        }
        if (remark.isNotEmpty()) {
            map["remarks"] = remark
        }
        // 使用正确的类型参数
        ApiManager.getInstance().requestPostLoading(
            this,
            "/sell/card/call_back",
            String::class.java,
            map,
            object : SubscriberListener<BaseResponse<String>>() {
                override fun onNext(t: BaseResponse<String>) {
                    if (t.success) {
                        this@NfcWreatActivity.finish()
                    } else {
                        // 处理搜索失败的情况
                        ToastUtil.show(t.msg)
                    }
                }
                override fun onError(e: Throwable?) {
                    super.onError(e)
                    ToastUtil.show("搜索失败: ${e?.message ?: "未知错误"}")
                }
            }
        )
    }
}
generallibrary/src/main/java/com/dayu/general/bean/card/BaseCard.kt
@@ -1,12 +1,12 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.baselibrary.tools.BaseCard
import com.dayu.general.bean.db.CardData
import com.dayu.general.dao.AppDataBase
import com.dayu.general.tool.CardCommon
import com.tencent.bugly.crashreport.CrashReport
open class BaseCard {
open class BaseCard : BaseCard() {
    var cardData: String? = null //标识码
    companion object {
@@ -33,25 +33,25 @@
    }
    /**
     * 前15个字节算术累加和 不含进位
     *
     * @param data 源数据
     * @return 16进制
     */
    fun getByteSum(data: ByteArray?): Byte {
        if (data != null) {
            var sum = 0
            for (b in data) {
                sum += b.toInt() and 0xFF // & 0xFF 可以将字节扩展为正整数,避免符号位的影响
            }
            var hex = HexUtil.get10to16CompleteHex(sum)
            hex = HexUtil.spaceHex(hex)
            val hexArr = hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray()
            return HexUtil.hexToByte(hexArr[hexArr.size - 1])
        }
        return 0
    }
//    /**
//     * 前15个字节算术累加和 不含进位
//     *
//     * @param data 源数据
//     * @return 16进制
//     */
//    fun getByteSum(data: ByteArray?): Byte {
//        if (data != null) {
//            var sum = 0
//            for (b in data) {
//                sum += b.toInt() and 0xFF // & 0xFF 可以将字节扩展为正整数,避免符号位的影响
//            }
//            var hex = HexUtil.get10to16CompleteHex(sum)
//            hex = HexUtil.spaceHex(hex)
//            val hexArr = hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }
//                .toTypedArray()
//            return HexUtil.hexToByte(hexArr[hexArr.size - 1])
//        }
//        return 0
//    }
}
generallibrary/src/main/java/com/dayu/general/bean/card/UserCard.kt
@@ -10,7 +10,7 @@
/**
 * 通用项目用户卡结构
 */
class UserCard : BaseCard(), Serializable {
class UserCard : BaseUserCardCard(), Serializable {
    var cardType: String = USER_CARD_TYPE_1 // 卡类型:A1终端写卡 A8刷卡开泵后值 A2叠加充值
    var areaNumber: Int = 0 // 国家行政区域号(12位BCD,精确到村)
    var userCode: String = "" // 用户编号BCD
@@ -30,10 +30,10 @@
        if (data == null || data.size < 3) {
            return false
        }
        val expectedBytes = arrayOf(getZeroBytes(), getOneBytes(), getTwoBytes())
        return data.zip(expectedBytes.toList()).all { (actual, expected) ->
            actual.contentEquals(expected)
        return data.zip(expectedBytes.toList()).all { (actual, expected) ->
            actual.contentEquals(expected)
        }
    }
@@ -47,7 +47,7 @@
    /**
     * 通过byte转bean
     */
     fun getBean(data: List<ByteArray>): UserCard? {
    override fun getBean(data: List<ByteArray>): UserCard? {
        try {
            val userCard = UserCard()
            // 解析第0块
@@ -75,7 +75,7 @@
                balance = HexUtil.get16To10LowHightByBytes(one.copyOfRange(1, 5))
                surplusWater = HexUtil.get16To10LowHightByBytes(one.copyOfRange(5, 9))
                electricPrice = HexUtil.hexToFloatLowHigh(one.copyOfRange(9, 11))
                // 解析充值时间
                val year = HexUtil.getBcdToInt(one[11])
                val month = HexUtil.getBcdToInt(one[12])
@@ -134,19 +134,19 @@
            val data = ByteArray(16)
            try {
                data[0] = projectCode.toByte()
                // 设置余额
                val balanceBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(balance))
                System.arraycopy(balanceBytes, 0, data, 1, 4)
                // 设置剩余水量
                val waterBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(surplusWater))
                System.arraycopy(waterBytes, 0, data, 5, 4)
                // 设置电价
                val priceBytes = HexUtil.hexToByteArray(HexUtil.floatToHexLowHigh(electricPrice))
                System.arraycopy(priceBytes, 0, data, 9, 2)
                // 设置充值时间
                rechargeDate?.let {
                    data[11] = HexUtil.getIntToBCD(it.get(Calendar.YEAR) % 100)[0]
@@ -154,7 +154,7 @@
                    data[13] = HexUtil.getIntToBCD(it.get(Calendar.DAY_OF_MONTH))[0]
                    data[14] = HexUtil.getIntToBCD(it.get(Calendar.HOUR_OF_DAY))[0]
                }
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
@@ -170,14 +170,14 @@
                // 备份余额和水量数据
                val balanceBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(balance))
                System.arraycopy(balanceBytes, 0, data, 1, 4)
                val waterBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(surplusWater))
                System.arraycopy(waterBytes, 0, data, 5, 4)
                // 设置水价
                val priceBytes = HexUtil.hexToByteArray(HexUtil.floatToHexLowHigh(waterPrice))
                System.arraycopy(priceBytes, 0, data, 9, 2)
                // 设置充值时间
                rechargeDate?.let {
                    data[11] = HexUtil.getIntToBCD(it.get(Calendar.YEAR) % 100)[0]
@@ -185,7 +185,7 @@
                    data[13] = HexUtil.getIntToBCD(it.get(Calendar.DAY_OF_MONTH))[0]
                    data[14] = HexUtil.getIntToBCD(it.get(Calendar.HOUR_OF_DAY))[0]
                }
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
@@ -194,7 +194,7 @@
        }
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
    fun getOneBytes(): ByteArray = One().toBytes()
    fun getTwoBytes(): ByteArray = Two().toBytes()
    override fun getZeroBytes(): ByteArray = Zero().toBytes()
    override fun getOneBytes(): ByteArray = One().toBytes()
    override fun getTwoBytes(): ByteArray = Two().toBytes()
}
generallibrary/src/main/java/com/dayu/general/tool/GeBaseHelper.kt
@@ -1,19 +1,18 @@
package com.dayu.general.tool
import android.content.Context
import android.util.Base64
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.baselibrary.tools.nfc.BaseNFCHelper
import java.nio.charset.StandardCharsets
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
open class GeBaseHelper(private val context: Context) : BaseNFCHelper() {
    companion object {
        init {
            System.loadLibrary("general-native-lib")
            try {
                System.loadLibrary("general-native-lib")
            } catch (e: UnsatisfiedLinkError) {
                e.printStackTrace()
            }
        }
    }
@@ -23,17 +22,20 @@
        try {
            // 获取所有扇区密钥
            val allKeys: String = getM1SectorKeySecure(context, 0)
            val keys: Array<String> =
                allKeys.split(",").dropLastWhile { it.isEmpty() }.toTypedArray()
            for (i in keys.indices) {
                val key = keys[i]
                listA_PS.add(HexUtil.hexToByteArray(key))
            if (allKeys.isNotEmpty()) {
                val keys: Array<String> = allKeys.split(",").dropLastWhile { it.isEmpty() }.toTypedArray()
                for (i in keys.indices) {
                    val key = keys[i]
                    if (key.isNotEmpty()) {
                        listA_PS.add(HexUtil.hexToByteArray(key))
                    }
                }
            }
            defauleKey = HexUtil.hexToByteArray("FFFFFFFFFFFF")
        } catch (e: Exception) {
            e.printStackTrace()
            // 设置默认密钥
            defauleKey = HexUtil.hexToByteArray("FFFFFFFFFFFF")
        }
    }
generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt
@@ -18,11 +18,11 @@
        /**
         * 单例初始化
         */
        @JvmStatic
        fun getInstance(intent: Intent, activity: Activity): NfcReadHelper {
            if (helper == null) {
                helper = NfcReadHelper(intent, activity)
            }
            helper!!.adapter.setIntent(intent)
            return helper!!
        }
    }
@@ -41,6 +41,18 @@
        }
    }
    fun getCardNumberNoClose():String{
        return try {
            adapter.cardNumberNoClose
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }
    /**
     * 获取卡片类型和卡号
     */
generallibrary/src/main/java/com/dayu/general/tool/NfcWreatHelper.kt
New file
@@ -0,0 +1,63 @@
package com.dayu.general.tool
import android.app.Activity
import android.content.Intent
import com.dayu.baselibrary.tools.nfc.NFCCallBack
import com.dayu.baselibrary.tools.nfc.NfcWriteAdapter
import com.dayu.general.bean.card.UserCard
class NfcWreatHelper private constructor(intent: Intent, activity: Activity) : GeBaseHelper(activity) {
    private val adapter: NfcWriteAdapter = NfcWriteAdapter(intent, activity)
    companion object {
        private var helper: NfcWreatHelper? = null
        /**
         * 单例初始化
         */
        @JvmStatic
        fun getInstance(intent: Intent, activity: Activity): NfcWreatHelper {
            if (helper == null) {
                helper = NfcWreatHelper(intent, activity)
            }
            helper!!.adapter.setIntent(intent)
            return helper!!
        }
    }
    /**
     * 写卡
     *
     * @param str 书写内容,16个字节
     * @param a   书写的扇区 (从0开始数)
     * @param b   书写的块(从0开始数)
     * @param
     */
    fun writeData(str: ByteArray?, a: Int, b: Int,callBack: NFCCallBack): Boolean {
        try {
            return adapter.writeData(str, a, b,callBack)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }
    /**
     * 写卡
     *
     * @param userCard 用户卡内容
     * @param
     */
    fun writeUserData(userCard: UserCard): Boolean {
        try {
            return adapter.writeUserData(userCard,7)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
        return false
    }
}
generallibrary/src/main/res/layout/activity_manager_read.xml
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewModel"
            type="com.dayu.general.model.CardInfoModel" />
@@ -25,14 +26,16 @@
        <LinearLayout
            android:id="@+id/data_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/titleBar"
            android:orientation="vertical"
            android:layout_height="wrap_content">
            android:visibility="gone">
            <LinearLayout
                android:layout_width="match_parent"
                android:orientation="vertical"
                android:layout_height="wrap_content">
                android:layout_height="wrap_content"
                android:orientation="vertical">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
@@ -44,15 +47,15 @@
                        android:layout_height="wrap_content"
                        android:text="卡号:"
                        android:textColor="#333333"
                        android:textSize="16sp"/>
                        android:textSize="16sp" />
                    <TextView
                        android:id="@+id/card_number_tv"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="@{viewModel.cardNumber}"
                        android:textColor="#333333"
                        android:textSize="16sp"
                        android:text="@{viewModel.cardNumber}"/>
                        android:textSize="16sp" />
                </LinearLayout>
                <LinearLayout
@@ -66,7 +69,7 @@
                        android:layout_height="wrap_content"
                        android:text="备注:"
                        android:textColor="#333333"
                        android:textSize="16sp"/>
                        android:textSize="16sp" />
                    <EditText
                        android:id="@+id/remark_et"
@@ -74,8 +77,9 @@
                        android:layout_height="wrap_content"
                        android:background="@null"
                        android:hint="请输入备注信息"
                        android:textSize="16sp"
                        android:text="@={viewModel.remark}"/>
                        android:text="@={viewModel.remark}"
                        android:textSize="16sp" />
                </LinearLayout>
            </LinearLayout>
@@ -122,5 +126,21 @@
                </LinearLayout>
            </androidx.cardview.widget.CardView>
        </LinearLayout>
        <TextView
            android:id="@+id/btn_next"
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:layout_alignParentBottom="true"
            android:layout_marginStart="16dp"
            android:layout_marginEnd="16dp"
            android:layout_marginBottom="16dp"
            android:background="#4285F4"
            android:gravity="center"
            android:visibility="gone"
            android:text="下一步"
            android:textColor="#FFFFFF"
            android:textSize="16sp" />
    </RelativeLayout>
</layout>
henanlibrary/src/main/java/com/dayu/henanlibrary/tools/NFCWriteHelper.java
@@ -34,6 +34,7 @@
        if (helper == null) {
            helper = new NFCWriteHelper(intent, activity);
        }
        helper.adapter.setIntent(intent);
        return helper;
    }
@@ -46,7 +47,7 @@
     */
    public boolean writeUserData(UserCardHN userCard) {
        try {
            return adapter.writeUserData(userCard);
            return adapter.writeUserData(userCard,1);
        } catch (Exception e) {
            e.printStackTrace();
        }
henanlibrary/src/main/java/com/dayu/henanlibrary/tools/NfcReadHelper.java
@@ -7,9 +7,6 @@
import com.dayu.baselibrary.tools.nfc.NfcReadAdapter;
import com.dayu.henanlibrary.card.UserCardHN;
import java.util.Collections;
import java.util.List;
/**
 * @author zx
 * @date 2018/4/23 14:31
@@ -39,6 +36,7 @@
        if (helper == null) {
            helper = new NfcReadHelper(intent, activity);
        }
        helper.adapter.setIntent(intent);
        return helper;
    }
qihealonelibrary/src/main/java/com/dayu/qihealonelibrary/tools/NFCWriteHelper.java
@@ -2,16 +2,10 @@
import android.app.Activity;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.util.Log;
import com.dayu.baselibrary.tools.HexUtil;
import com.dayu.baselibrary.tools.nfc.NfcWriteAdapter;
import com.dayu.qihealonelibrary.card.UserCard;
import java.io.IOException;
/**
 * @author zx
@@ -41,6 +35,7 @@
        if (helper == null) {
            helper = new NFCWriteHelper(intent, activity);
        }
        helper.adapter.setIntent(intent);
        return helper;
    }
@@ -53,7 +48,7 @@
     */
    public boolean writeUserData(UserCard userCard) {
        try {
            return adapter.writeUserData(userCard);
            return adapter.writeUserData(userCard,1);
        } catch (Exception e) {
            e.printStackTrace();
        }
qihealonelibrary/src/main/java/com/dayu/qihealonelibrary/tools/NfcReadHelper.java
@@ -39,6 +39,7 @@
        if (helper == null) {
            helper = new NfcReadHelper(intent, activity);
        }
        helper.adapter.setIntent(intent);
        return helper;
    }
qiheonlinelibrary/src/main/java/com/dayu/qiheonlinelibrary/tools/NFCWriteHelper.java
@@ -2,18 +2,10 @@
import android.app.Activity;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.util.Log;
import com.dayu.baselibrary.tools.HexUtil;
import com.dayu.baselibrary.tools.nfc.NfcWriteAdapter;
import com.dayu.qiheonlinelibrary.card.UserCard;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
 * @author zx
@@ -43,6 +35,7 @@
        if (helper == null) {
            helper = new NFCWriteHelper(intent, activity);
        }
        helper.adapter.setIntent(intent);
        return helper;
    }
@@ -55,7 +48,7 @@
     */
    public boolean writeUserData(UserCard userCard) {
        try {
            return adapter.writeUserData(userCard);
            return adapter.writeUserData(userCard,1);
        } catch (Exception e) {
            e.printStackTrace();
        }
qiheonlinelibrary/src/main/java/com/dayu/qiheonlinelibrary/tools/NfcReadHelper.java
@@ -38,6 +38,7 @@
        if (helper == null) {
            helper = new NfcReadHelper(intent, activity);
        }
        helper.adapter.setIntent(intent);
        return helper;
    }