概述
本文檔記錄了在Android POS應用開發過程中遇到的兩個關鍵問題及其解決方案:
UnsatisfiedLinkError: couldn't find "libnative.so"
錯誤ActivityNotFoundException
錯誤- 商戶信息一致性檢查繞過
問題1:UnsatisfiedLinkError - libnative.so庫加載失敗
問題描述
應用在ARM64架構設備上運行時出現以下完整錯誤信息:
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/~~9LvQGgl7HMUBJBdLUqNzVw==/com.rkxch.hspos-bYGBfqmXoa7gEGiO_MP_-g==/base.apk"],nativeLibraryDirectories=[/data/app/~~9LvQGgl7HMUBJBdLUqNzVw==/com.rkxch.hspos-bYGBfqmXoa7gEGiO_MP_-g==/lib/arm64, /system/lib64, /system_ext/lib64]]] couldn't find "libnative.so"at java.lang.Runtime.loadLibrary0(Runtime.java:1071)at java.lang.Runtime.loadLibrary0(Runtime.java:1007)at java.lang.System.loadLibrary(System.java:1667)at com.ccb.clientauth.ClientAuth.<clinit>(ClientAuth.java:21)at com.rkxch.hspos.ui.common.AuthUtil.getAuthCode(AuthUtil.java:18)at com.rkxch.hspos.ui.login.LoginActivity.getMerchantId(LoginActivity.java:215)at com.rkxch.hspos.ui.login.LoginActivity.onCreate(LoginActivity.java:179)at android.app.Activity.performCreate(Activity.java:8051)at android.app.Activity.performCreate(Activity.java:8031)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)at android.os.Handler.dispatchMessage(Handler.java:106)at android.os.Looper.loopOnce(Looper.java:201)at android.os.Looper.loop(Looper.java:288)at android.app.ActivityThread.main(ActivityThread.java:7872)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
根本原因
clientauth-release.aar
庫中只包含armeabi-v7a
架構的libnative.so
文件- 設備運行在
arm64
架構上,無法找到對應架構的native庫 - Android系統默認不會在ARM64設備上加載armeabi-v7a架構的庫
解決方案
步驟1:檢查AAR文件內容
jar -tf app\libs\clientauth-release.aar | Select-String -Pattern "lib/"
確認AAR文件中只包含:
lib/armeabi-v7a/libnative.so
步驟2:修改build.gradle配置
問題原因: 應用運行在ARM64設備上,但native庫只提供了armeabi-v7a版本,系統默認會嘗試加載arm64-v8a版本導致找不到庫文件。
解決方案: 通過配置ABI過濾器,明確告訴Android系統應用只支持armeabi-v7a架構,利用ARM64設備的向下兼容性來運行32位庫。
具體操作:
- 打開
app/build.gradle
文件 - 在
android
塊的defaultConfig
部分添加ndk
配置:
android {compileSdkVersion 30buildToolsVersion "30.0.3"defaultConfig {applicationId "com.example.hspos"minSdkVersion 21targetSdkVersion 30versionCode 1versionName "1.0"// 添加ABI過濾器,只支持armeabi-v7a架構ndk {abiFilters "armeabi-v7a"}testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}// 其他配置...
}
配置說明:
abiFilters "armeabi-v7a"
限制應用只支持armeabi-v7a架構- 這樣配置后,即使在ARM64設備上,系統也會使用armeabi-v7a版本的native庫
- ARM64設備具有向下兼容性,可以正常運行32位的armeabi-v7a代碼
步驟3:重新構建項目
./gradlew clean build
技術原理
abiFilters "armeabi-v7a"
配置告訴Android系統只支持armeabi-v7a架構- ARM64設備具有向下兼容性,可以運行armeabi-v7a架構的代碼
- 這種配置確保應用在ARM64設備上能夠正確加載armeabi-v7a的native庫
問題2:ActivityNotFoundException - 外部應用調用失敗
問題描述
應用嘗試啟動建行支付應用時出現以下完整錯誤信息:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rkxch.hspos/com.ccb.smartpos.bankpay.ui.MainActivity}: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.ccb.smartpos.bankpay/com.ccb.smartpos.bankpay.ui.MainActivity}; have you declared this activity in your AndroidManifest.xml?at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3654)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)at android.app.ActivityThread.-wrap12(Unknown Source:0)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)at android.os.Handler.dispatchMessage(Handler.java:106)at android.os.Looper.loopOnce(Looper.java:201)at android.os.Looper.loop(Looper.java:288)at android.app.ActivityThread.main(ActivityThread.java:7872)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.ccb.smartpos.bankpay/com.ccb.smartpos.bankpay.ui.MainActivity}; have you declared this activity in your AndroidManifest.xml?at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2005)at android.app.Instrumentation.execStartActivity(Instrumentation.java:1673)at android.app.Activity.startActivityForResult(Activity.java:5315)at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:676)at android.app.Activity.startActivityForResult(Activity.java:5273)at com.rkxch.hspos.ui.login.LoginActivity.getMerchantId(LoginActivity.java:230)at com.rkxch.hspos.ui.login.LoginActivity.onCreate(LoginActivity.java:179)at android.app.Activity.performCreate(Activity.java:8051)at android.app.Activity.performCreate(Activity.java:8031)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)... 10 more
根本原因
- 應用嘗試通過
ComponentName
顯式啟動建行支付應用的Activity - 目標設備上未安裝建行支付應用 (
com.ccb.smartpos.bankpay
) - 缺少異常處理機制,導致應用崩潰
解決方案
涉及的文件和方法
LoginActivity.java
-getMerchantId()
方法ScanPaySecondStepActivity.java
-consumeByScan()
和queryTransInfo()
方法SwipeCardSecondStepActivity.java
-consumeBySwipe()
方法
修改示例(以LoginActivity為例)
修改前:
private void getMerchantId() {String authIndex = null;String authCode = null;Intent intent = new Intent();intent.setComponent(new ComponentName("com.ccb.smartpos.bankpay", "com.ccb.smartpos.bankpay.ui.MainActivity"));// ... 其他代碼startActivityForResult(intent, 999);
}
修改后:
private void getMerchantId() {try {String authIndex = null;String authCode = null;Intent intent = new Intent();intent.setComponent(new ComponentName("com.ccb.smartpos.bankpay", "com.ccb.smartpos.bankpay.ui.MainActivity"));// ... 其他代碼startActivityForResult(intent, 999);} catch (Exception e) {Log.e(TAG, "CCB bankpay app not found or not available: " + e.getMessage());merchantId = "DEFAULT_MERCHANT_ID";Toast.makeText(this, "CCB銀行支付應用未安裝,使用默認配置", Toast.LENGTH_SHORT).show();}
}
異常處理策略
- 捕獲異常:使用try-catch塊捕獲所有可能的異常
- 日志記錄:記錄詳細的錯誤信息便于調試
- 用戶提示:顯示友好的中文提示信息
- 默認處理:設置默認值確保應用繼續運行
- 防止崩潰:確保應用在外部依賴缺失時仍能正常工作
問題3:商戶信息一致性檢查繞過
問題描述
應用在登錄時會檢查登錄用戶的商戶信息與POS設備的商戶信息是否一致,不一致時會阻止登錄。
解決方案
修改LoginActivity.java
將商戶信息一致性檢查代碼注釋掉:
修改前:
if (merchantId != null) { // 從建行收單應用中讀取到商戶編號List<Supplier> list = user.getSupplierList();boolean matched = false;for (Supplier supplier : list) {if (supplier.getMerchantId().equals(merchantId)) {matchSupplier = supplier;matched = true;break;}}if (!matched) {Toast.makeText(LoginActivity.this, "登錄用戶的商戶信息與POS的商戶信息不一致", Toast.LENGTH_LONG).show();matchSupplier = null;}
}
修改后:
// 跳過商戶信息一致性檢查
// if (merchantId != null) { // 從建行收單應用中讀取到商戶編號
// List<Supplier> list = user.getSupplierList();
//
// boolean matched = false;
// for (Supplier supplier : list) {
// if (supplier.getMerchantId().equals(merchantId)) {
// matchSupplier = supplier;
// matched = true;
// break;
// }
// }
//
// if (!matched) {
// Toast.makeText(LoginActivity.this, "登錄用戶的商戶信息與POS的商戶信息不一致", Toast.LENGTH_LONG).show();
// matchSupplier = null;
// }
// }
構建和驗證
構建命令
# 清理并構建Debug版本
./gradlew clean assembleDebug# 或者構建所有版本
./gradlew clean build
驗證步驟
-
檢查APK內容:
jar -tf app\build\outputs\apk\debug\app-debug.apk | Select-String -Pattern "lib/"
確認輸出包含:
lib/armeabi-v7a/libnative.so
-
安裝測試:在ARM64設備上安裝APK并測試native庫加載
-
功能測試:驗證應用在建行支付應用未安裝的情況下不會崩潰
最佳實踐和建議
1. Native庫兼容性
- 在發布應用前,確保所有依賴的AAR文件包含目標架構的native庫
- 考慮使用
splits
配置為不同架構生成單獨的APK - 定期檢查第三方庫的架構支持情況
2. 外部應用依賴處理
- 始終為外部應用調用添加異常處理
- 提供降級方案或默認行為
- 使用
PackageManager.resolveActivity()
檢查目標應用是否存在
3. 錯誤處理策略
- 實現全局異常處理機制
- 提供用戶友好的錯誤提示
- 記錄詳細的錯誤日志便于問題排查
4. 測試建議
- 在不同架構的設備上進行測試
- 模擬外部依賴缺失的場景
- 進行兼容性測試確保應用穩定性
總結
通過以上解決方案,我們成功解決了:
- ? ARM64設備上native庫加載失敗的問題
- ? 外部應用調用導致的崩潰問題
- ? 商戶信息一致性檢查的限制
這些修改確保了應用在各種環境下都能穩定運行,提升了用戶體驗和應用的健壯性。