@onekeyfe/react-native-lite-card 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +37 -0
- package/ReactNativeLiteCard.podspec +22 -0
- package/android/build.gradle +79 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/config/command.json +205 -0
- package/android/src/main/cpp/CMakeLists.txt +19 -0
- package/android/src/main/cpp/validation.c +227 -0
- package/android/src/main/cpp/validation.h +19 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/LoggerManager.kt +35 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardModule.kt +420 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardPackage.kt +33 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/keys/KeysNativeProvider.kt +13 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/Exceptions.kt +58 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/NfcUtils.kt +142 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/broadcast/NfcStatusChangeBroadcastReceiver.kt +56 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/gpchannel/GPChannelNatives.kt +32 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/NfcConstant.kt +38 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/OnekeyLiteCard.kt +236 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/APDUParam.kt +17 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardInfo.java +84 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardResponse.java +37 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardState.kt +10 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/ParsedCertInfo.java +39 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SecureChanelParam.java +113 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SendResponse.kt +26 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/CommandGenerator.kt +178 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/Connection.kt +439 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/GPCAPDUGenerator.kt +56 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/EventUtils.kt +14 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/GpsUtil.kt +38 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/HexUtils.java +93 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/LogUtil.kt +11 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/MiUtil.kt +93 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/NfcPermissionUtils.kt +24 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/Utils.java +437 -0
- package/android/src/main/jniLibs/arm64-v8a/libgpchannelNDK.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libgpchannelNDK.so +0 -0
- package/ios/Classes/OKLiteCommand/OKLiteCommandModal.h +39 -0
- package/ios/Classes/OKLiteCommand/OKLiteCommandModal.m +143 -0
- package/ios/Classes/OKLiteCommand/OKLiteCommandTool.h +28 -0
- package/ios/Classes/OKLiteCommand/OKLiteCommandTool.m +53 -0
- package/ios/Classes/OKNFCBridge.h +28 -0
- package/ios/Classes/OKNFCBridge.mm +221 -0
- package/ios/Classes/OKNFCLiteDefine.h +108 -0
- package/ios/Classes/OKNFTLite/OKLiteProtocol.h +37 -0
- package/ios/Classes/OKNFTLite/OKLiteV1.h +41 -0
- package/ios/Classes/OKNFTLite/OKLiteV1.m +609 -0
- package/ios/Classes/OKNFTLite/OKLiteV2.h +17 -0
- package/ios/Classes/OKNFTLite/OKLiteV2.m +132 -0
- package/ios/Classes/OKNFTLite/OKNFCManager.h +40 -0
- package/ios/Classes/OKNFTLite/OKNFCManager.m +330 -0
- package/ios/Classes/Utils/NFCConfig.h +19 -0
- package/ios/Classes/Utils/NFCConfig.m +18 -0
- package/ios/Classes/Utils/NSData+OKNFCHexData.h +17 -0
- package/ios/Classes/Utils/NSData+OKNFCHexData.m +24 -0
- package/ios/Classes/Utils/NSData+StringToData.h +12 -0
- package/ios/Classes/Utils/NSData+StringToData.m +25 -0
- package/ios/Classes/Utils/NSString+OKAdd.h +14 -0
- package/ios/Classes/Utils/NSString+OKAdd.m +40 -0
- package/ios/Classes/Utils/NSString+OKNFCHexStr.h +18 -0
- package/ios/Classes/Utils/NSString+OKNFCHexStr.m +38 -0
- package/ios/Classes/Utils/OKNFCUtility.h +18 -0
- package/ios/Classes/Utils/OKNFCUtility.m +22 -0
- package/ios/Classes/Utils/OKTools.h +17 -0
- package/ios/Classes/Utils/OKTools.m +21 -0
- package/ios/GPChannelSDKCore.xcframework/Info.plist +52 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/GPChannelSDKCore +0 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Headers/GPChannelSDK.h +315 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Headers/GPChannelSDKCore.h +19 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Info.plist +0 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Modules/module.modulemap +7 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/_CodeSignature/CodeResources +147 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/GPChannelSDKCore +0 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Headers/GPChannelSDK.h +315 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Headers/GPChannelSDKCore.h +19 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Info.plist +0 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Modules/module.modulemap +7 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/_CodeSignature/CodeResources +147 -0
- package/ios/ReactNativeLiteCard.h +5 -0
- package/ios/ReactNativeLiteCard.mm +222 -0
- package/lib/module/NativeReactNativeLiteCard.js +25 -0
- package/lib/module/NativeReactNativeLiteCard.js.map +1 -0
- package/lib/module/index.js +71 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeReactNativeLiteCard.d.ts +59 -0
- package/lib/typescript/src/NativeReactNativeLiteCard.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +23 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +168 -0
- package/src/NativeReactNativeLiteCard.ts +112 -0
- package/src/index.tsx +94 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.utils
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.provider.Settings
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
object GpsUtil {
|
|
9
|
+
/**
|
|
10
|
+
* 判断GPS是否开启,GPS或者AGPS开启一个就认为是开启的
|
|
11
|
+
* @param context
|
|
12
|
+
* @return true 表示开启
|
|
13
|
+
*/
|
|
14
|
+
fun isOpen(context: Context?): Boolean {
|
|
15
|
+
if (context == null) {
|
|
16
|
+
return true
|
|
17
|
+
}
|
|
18
|
+
var locationMode = 0
|
|
19
|
+
val locationProviders: String
|
|
20
|
+
|
|
21
|
+
locationMode = try {
|
|
22
|
+
Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE)
|
|
23
|
+
} catch (e: Settings.SettingNotFoundException) {
|
|
24
|
+
e.printStackTrace()
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
return locationMode != Settings.Secure.LOCATION_MODE_OFF
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 跳转设置 打开GPS
|
|
32
|
+
* @param context
|
|
33
|
+
*/
|
|
34
|
+
fun openGPS(context: Context) {
|
|
35
|
+
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
|
|
36
|
+
context.startActivity(intent)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.utils;
|
|
2
|
+
|
|
3
|
+
import java.math.BigInteger;
|
|
4
|
+
import java.util.Collections;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @author liyan
|
|
8
|
+
*/
|
|
9
|
+
public class HexUtils {
|
|
10
|
+
|
|
11
|
+
public static byte[] hexString2Bytes(String hex) {
|
|
12
|
+
if (hex == null) return new byte[0];
|
|
13
|
+
return String2Bytes(hex, 16);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
private static byte[] String2Bytes(String str, int digit) {
|
|
17
|
+
byte[] bArray = new BigInteger("10" + str, digit).toByteArray();
|
|
18
|
+
|
|
19
|
+
byte[] ret = new byte[bArray.length - 1];
|
|
20
|
+
for (int i = 0; i < ret.length; i++) {
|
|
21
|
+
ret[i] = bArray[i + 1];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return ret;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
public static String stringToHexString(String s) {
|
|
29
|
+
if (s == null) return "";
|
|
30
|
+
String str = "";
|
|
31
|
+
for (int i = 0; i < s.length(); i++) {
|
|
32
|
+
int ch = s.charAt(i);
|
|
33
|
+
String s4 = Integer.toHexString(ch);
|
|
34
|
+
str = str + s4;
|
|
35
|
+
}
|
|
36
|
+
return str;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 将字节数组转换成十六进制的字符串
|
|
41
|
+
*
|
|
42
|
+
* @param bt 字节数组
|
|
43
|
+
* @param start 起始下标
|
|
44
|
+
* @param end 终止下标
|
|
45
|
+
*/
|
|
46
|
+
public static String byteArr2HexStr(byte[] bt, int start, int end) {
|
|
47
|
+
return byteArr2HexStr(bt, start, end, "");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 将字节数组转换成十六进制的字符串
|
|
52
|
+
*
|
|
53
|
+
* @param bt 字节数组
|
|
54
|
+
*/
|
|
55
|
+
public static String byteArr2HexStr(byte[] bt) {
|
|
56
|
+
if (bt == null) return "";
|
|
57
|
+
if (bt.length == 0) return "";
|
|
58
|
+
return byteArr2HexStr(bt, 0, bt.length, "");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 将字节数组转换成十六进制的字符串
|
|
63
|
+
*
|
|
64
|
+
* @param bt 字节数组
|
|
65
|
+
* @param start 起始下标
|
|
66
|
+
* @param end 终止下标
|
|
67
|
+
* @param sep 每个字节之间的分割字符串
|
|
68
|
+
*/
|
|
69
|
+
public static String byteArr2HexStr(byte[] bt, int start, int end, String sep) {
|
|
70
|
+
if (bt == null || bt.length < end || start < 0 || start >= end) {
|
|
71
|
+
throw new RuntimeException("param format error");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
StringBuffer sb = new StringBuffer();
|
|
75
|
+
for (int i = start; i < end; i++) {
|
|
76
|
+
sb.append(byte2HexStr(bt[i])).append(sep);
|
|
77
|
+
}
|
|
78
|
+
return sb.toString();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 将byte转换成对应的十六进制字符串(如:byte值0x3D转换成字符串"3D")
|
|
83
|
+
*
|
|
84
|
+
* @return 返回字符串长度一定为2
|
|
85
|
+
*/
|
|
86
|
+
public static String byte2HexStr(byte b) {
|
|
87
|
+
int i = (b & 0xF0) >> 4;
|
|
88
|
+
int j = (b & 0x0F);
|
|
89
|
+
char c = (char) (i > 9 ? 'A' + i % 10 : '0' + i);
|
|
90
|
+
char d = (char) (j > 9 ? 'A' + j % 10 : '0' + j);
|
|
91
|
+
return "" + c + d;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.utils
|
|
2
|
+
|
|
3
|
+
import so.onekey.app.wallet.lite.onekeyLite.NfcConstant
|
|
4
|
+
import so.onekey.app.wallet.lite.LoggerManager
|
|
5
|
+
|
|
6
|
+
object LogUtil {
|
|
7
|
+
@JvmStatic
|
|
8
|
+
fun printLog(tag: String, msg: String) {
|
|
9
|
+
if (NfcConstant.DEBUG) LoggerManager.getInstance()?.logInfo("$tag: $msg")
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.utils
|
|
2
|
+
|
|
3
|
+
import android.app.AppOpsManager
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.Intent
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.provider.Settings
|
|
9
|
+
import android.util.Log
|
|
10
|
+
import androidx.annotation.IntDef
|
|
11
|
+
import androidx.annotation.RequiresApi
|
|
12
|
+
import so.onekey.app.wallet.lite.utils.MiUtil.PermissionResult.Companion.PERMISSION_ASK
|
|
13
|
+
import so.onekey.app.wallet.lite.utils.MiUtil.PermissionResult.Companion.PERMISSION_DENIED
|
|
14
|
+
import so.onekey.app.wallet.lite.utils.MiUtil.PermissionResult.Companion.PERMISSION_GRANTED
|
|
15
|
+
import so.onekey.app.wallet.lite.utils.MiUtil.PermissionResult.Companion.PERMISSION_UNKNOWN
|
|
16
|
+
|
|
17
|
+
object MiUtil {
|
|
18
|
+
val TAG = MiUtil::class.simpleName
|
|
19
|
+
|
|
20
|
+
@IntDef(value = [PERMISSION_GRANTED, PERMISSION_DENIED, PERMISSION_ASK, PERMISSION_UNKNOWN])
|
|
21
|
+
@kotlin.annotation.Retention(
|
|
22
|
+
AnnotationRetention.SOURCE
|
|
23
|
+
)
|
|
24
|
+
annotation class PermissionResult {
|
|
25
|
+
companion object {
|
|
26
|
+
/**
|
|
27
|
+
* Permission check result: this is returned by [.check]
|
|
28
|
+
* if the permission has been granted to the given package.
|
|
29
|
+
*/
|
|
30
|
+
const val PERMISSION_GRANTED = 0
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Permission check result: this is returned by [.check]
|
|
34
|
+
* if the permission has not been granted to the given package.
|
|
35
|
+
*/
|
|
36
|
+
const val PERMISSION_DENIED = -1
|
|
37
|
+
|
|
38
|
+
const val PERMISSION_ASK = 1
|
|
39
|
+
|
|
40
|
+
const val PERMISSION_UNKNOWN = 2
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 检测NFC权限是否有授权.
|
|
46
|
+
*/
|
|
47
|
+
@PermissionResult
|
|
48
|
+
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
|
49
|
+
fun checkNfcPermission(context: Context): Int {
|
|
50
|
+
try {
|
|
51
|
+
val mAppOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
|
|
52
|
+
val pkg = context.applicationContext.packageName
|
|
53
|
+
val uid = context.applicationInfo.uid
|
|
54
|
+
val appOpsClass = Class.forName(AppOpsManager::class.java.name)
|
|
55
|
+
val checkOpNoThrowMethod = appOpsClass.getDeclaredMethod(
|
|
56
|
+
"checkOpNoThrow", Integer.TYPE, Integer.TYPE,
|
|
57
|
+
String::class.java
|
|
58
|
+
)
|
|
59
|
+
//the ops of NFC is 10016,check /data/system/appops/xxx.xml
|
|
60
|
+
val invoke = checkOpNoThrowMethod.invoke(mAppOps, 10016, uid, pkg)
|
|
61
|
+
if (invoke == null) {
|
|
62
|
+
Log.d(TAG,
|
|
63
|
+
"MIUI check permission checkOpNoThrowMethod(AppOpsManager) invoke result is null"
|
|
64
|
+
)
|
|
65
|
+
return PERMISSION_UNKNOWN
|
|
66
|
+
}
|
|
67
|
+
val result = invoke.toString()
|
|
68
|
+
Log.d(TAG,
|
|
69
|
+
"MIUI check permission checkOpNoThrowMethod(AppOpsManager) invoke result = $result"
|
|
70
|
+
)
|
|
71
|
+
when (result) {
|
|
72
|
+
"0" -> return PERMISSION_GRANTED
|
|
73
|
+
"1" -> return PERMISSION_DENIED
|
|
74
|
+
"5" -> return PERMISSION_ASK
|
|
75
|
+
}
|
|
76
|
+
} catch (e: Exception) {
|
|
77
|
+
Log.d(TAG, "check nfc permission fail ${e.message}", e)
|
|
78
|
+
}
|
|
79
|
+
return PERMISSION_UNKNOWN
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fun intentToAppSetting(context: Context): Boolean {
|
|
83
|
+
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
|
84
|
+
intent.data = Uri.fromParts("package", context.packageName, null)
|
|
85
|
+
return try {
|
|
86
|
+
context.startActivity(intent)
|
|
87
|
+
true
|
|
88
|
+
} catch (e: Exception) {
|
|
89
|
+
Log.d(TAG, "open app setting fail ${e.message}", e)
|
|
90
|
+
false
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.utils
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.os.Build
|
|
5
|
+
|
|
6
|
+
object NfcPermissionUtils {
|
|
7
|
+
|
|
8
|
+
inline fun checkPermission(activity: Activity, doNext: () -> Unit): Int {
|
|
9
|
+
return if ("xiaomi".equals(Build.MANUFACTURER, true)) {
|
|
10
|
+
return checkMiuiPermission(activity, doNext)
|
|
11
|
+
} else {
|
|
12
|
+
doNext.invoke()
|
|
13
|
+
0
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
inline fun checkMiuiPermission(activity: Activity, doNext: () -> Unit): Int {
|
|
18
|
+
when (MiUtil.checkNfcPermission(activity)) {
|
|
19
|
+
MiUtil.PermissionResult.PERMISSION_GRANTED -> doNext.invoke()
|
|
20
|
+
else -> {}
|
|
21
|
+
}
|
|
22
|
+
return MiUtil.checkNfcPermission(activity)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.utils;
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint;
|
|
4
|
+
import android.app.Activity;
|
|
5
|
+
import android.app.ActivityManager;
|
|
6
|
+
import android.app.Application;
|
|
7
|
+
import android.app.Application.ActivityLifecycleCallbacks;
|
|
8
|
+
import android.content.Context;
|
|
9
|
+
import android.os.Bundle;
|
|
10
|
+
|
|
11
|
+
import androidx.annotation.NonNull;
|
|
12
|
+
import androidx.annotation.Nullable;
|
|
13
|
+
|
|
14
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
15
|
+
|
|
16
|
+
import org.jetbrains.annotations.NotNull;
|
|
17
|
+
|
|
18
|
+
import java.lang.reflect.Field;
|
|
19
|
+
import java.lang.reflect.InvocationTargetException;
|
|
20
|
+
import java.util.HashMap;
|
|
21
|
+
import java.util.LinkedList;
|
|
22
|
+
import java.util.List;
|
|
23
|
+
import java.util.Map;
|
|
24
|
+
import java.util.regex.Matcher;
|
|
25
|
+
import java.util.regex.Pattern;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* <pre>
|
|
29
|
+
* author:
|
|
30
|
+
* ___ ___ ___ ___
|
|
31
|
+
* _____ / /\ /__/\ /__/| / /\
|
|
32
|
+
* / /::\ / /::\ \ \:\ | |:| / /:/
|
|
33
|
+
* / /:/\:\ ___ ___ / /:/\:\ \ \:\ | |:| /__/::\
|
|
34
|
+
* / /:/~/::\ /__/\ / /\ / /:/~/::\ _____\__\:\ __| |:| \__\/\:\
|
|
35
|
+
* /__/:/ /:/\:| \ \:\ / /:/ /__/:/ /:/\:\ /__/::::::::\ /__/\_|:|____ \ \:\
|
|
36
|
+
* \ \:\/:/~/:/ \ \:\ /:/ \ \:\/:/__\/ \ \:\~~\~~\/ \ \:\/:::::/ \__\:\
|
|
37
|
+
* \ \::/ /:/ \ \:\/:/ \ \::/ \ \:\ ~~~ \ \::/~~~~ / /:/
|
|
38
|
+
* \ \:\/:/ \ \::/ \ \:\ \ \:\ \ \:\ /__/:/
|
|
39
|
+
* \ \::/ \__\/ \ \:\ \ \:\ \ \:\ \__\/
|
|
40
|
+
* \__\/ \__\/ \__\/ \__\/
|
|
41
|
+
* blog : http://blankj.com
|
|
42
|
+
* time : 16/12/08
|
|
43
|
+
* desc : utils about initialization
|
|
44
|
+
* </pre>
|
|
45
|
+
*/
|
|
46
|
+
public final class Utils {
|
|
47
|
+
|
|
48
|
+
@SuppressLint("StaticFieldLeak")
|
|
49
|
+
private static Application sApplication;
|
|
50
|
+
|
|
51
|
+
static final ActivityLifecycleImpl ACTIVITY_LIFECYCLE = new ActivityLifecycleImpl();
|
|
52
|
+
|
|
53
|
+
private Utils() {
|
|
54
|
+
throw new UnsupportedOperationException("u can't instantiate me...");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Init utils.
|
|
59
|
+
*
|
|
60
|
+
* <p>Init it in the class of Application.
|
|
61
|
+
*
|
|
62
|
+
* @param context context
|
|
63
|
+
*/
|
|
64
|
+
public static void init(@NonNull final ReactApplicationContext context) {
|
|
65
|
+
Utils.getActivityLifecycle().setTopActivity(context.getCurrentActivity());
|
|
66
|
+
init((Application) context.getApplicationContext());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Init utils.
|
|
71
|
+
*
|
|
72
|
+
* <p>Init it in the class of Application.
|
|
73
|
+
*
|
|
74
|
+
* @param app application
|
|
75
|
+
*/
|
|
76
|
+
public static void init(@NonNull final Application app) {
|
|
77
|
+
if (sApplication == null) {
|
|
78
|
+
Utils.sApplication = app;
|
|
79
|
+
Utils.sApplication.registerActivityLifecycleCallbacks(ACTIVITY_LIFECYCLE);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Return the context of Application object.
|
|
85
|
+
*
|
|
86
|
+
* @return the context of Application object
|
|
87
|
+
*/
|
|
88
|
+
public static Application getApp() {
|
|
89
|
+
if (sApplication != null) {
|
|
90
|
+
return sApplication;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
@SuppressLint("PrivateApi")
|
|
94
|
+
Class<?> activityThread = Class.forName("android.app.ActivityThread");
|
|
95
|
+
Object at = activityThread.getMethod("currentActivityThread").invoke(null);
|
|
96
|
+
Object app = activityThread.getMethod("getApplication").invoke(at);
|
|
97
|
+
if (app == null) {
|
|
98
|
+
throw new NullPointerException("u should init first");
|
|
99
|
+
}
|
|
100
|
+
init((Application) app);
|
|
101
|
+
return sApplication;
|
|
102
|
+
} catch (NoSuchMethodException e) {
|
|
103
|
+
e.printStackTrace();
|
|
104
|
+
} catch (IllegalAccessException e) {
|
|
105
|
+
e.printStackTrace();
|
|
106
|
+
} catch (InvocationTargetException e) {
|
|
107
|
+
e.printStackTrace();
|
|
108
|
+
} catch (ClassNotFoundException e) {
|
|
109
|
+
e.printStackTrace();
|
|
110
|
+
}
|
|
111
|
+
throw new NullPointerException("u should init first");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public static ActivityLifecycleImpl getActivityLifecycle() {
|
|
115
|
+
return ACTIVITY_LIFECYCLE;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public static LinkedList<Activity> getActivityList() {
|
|
119
|
+
return ACTIVITY_LIFECYCLE.mActivityList;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@NotNull
|
|
123
|
+
public static Context getTopActivityOrApp() {
|
|
124
|
+
if (isAppForeground()) {
|
|
125
|
+
Activity topActivity = ACTIVITY_LIFECYCLE.getTopActivity();
|
|
126
|
+
return topActivity == null ? Utils.getApp() : topActivity;
|
|
127
|
+
} else {
|
|
128
|
+
return Utils.getApp();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@Nullable
|
|
133
|
+
public static Activity getTopActivity() {
|
|
134
|
+
if (!isAppForeground()) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
return ACTIVITY_LIFECYCLE.getTopActivity();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Finish all of activities.
|
|
142
|
+
*/
|
|
143
|
+
public static void finishAllActivities() {
|
|
144
|
+
finishAllActivities(false);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Finish all of activities.
|
|
149
|
+
*
|
|
150
|
+
* @param isLoadAnim True to use animation for the outgoing activity, false otherwise.
|
|
151
|
+
*/
|
|
152
|
+
public static void finishAllActivities(final boolean isLoadAnim) {
|
|
153
|
+
List<Activity> activityList = getActivityList();
|
|
154
|
+
for (Activity act : activityList) {
|
|
155
|
+
// sActivityList remove the index activity at onActivityDestroyed
|
|
156
|
+
act.finish();
|
|
157
|
+
if (!isLoadAnim) {
|
|
158
|
+
act.overridePendingTransition(0, 0);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Finish all of activities except the newest activity.
|
|
165
|
+
*/
|
|
166
|
+
public static void finishAllActivitiesExceptNewest() {
|
|
167
|
+
finishAllActivitiesExceptNewest(false);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Finish all of activities except the newest activity.
|
|
172
|
+
*
|
|
173
|
+
* @param isLoadAnim True to use animation for the outgoing activity, false otherwise.
|
|
174
|
+
*/
|
|
175
|
+
public static void finishAllActivitiesExceptNewest(final boolean isLoadAnim) {
|
|
176
|
+
List<Activity> activities = getActivityList();
|
|
177
|
+
for (int i = 1; i < activities.size(); i++) {
|
|
178
|
+
finishActivity(activities.get(i), isLoadAnim);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public static void finishActivity(@NonNull final Activity activity) {
|
|
183
|
+
finishActivity(activity, false);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public static void finishActivity(@NonNull final Activity activity, final boolean isLoadAnim) {
|
|
187
|
+
activity.finish();
|
|
188
|
+
if (!isLoadAnim) {
|
|
189
|
+
activity.overridePendingTransition(0, 0);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Finish the activity.
|
|
195
|
+
*
|
|
196
|
+
* @param clz The activity class.
|
|
197
|
+
*/
|
|
198
|
+
public static void finishActivity(@NonNull final Class<? extends Activity> clz) {
|
|
199
|
+
finishActivity(clz, false);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Finish the activity.
|
|
204
|
+
*
|
|
205
|
+
* @param clz The activity class.
|
|
206
|
+
* @param isLoadAnim True to use animation for the outgoing activity, false otherwise.
|
|
207
|
+
*/
|
|
208
|
+
public static void finishActivity(
|
|
209
|
+
@NonNull final Class<? extends Activity> clz, final boolean isLoadAnim) {
|
|
210
|
+
List<Activity> activities = getActivityList();
|
|
211
|
+
for (Activity activity : activities) {
|
|
212
|
+
if (activity.getClass().equals(clz)) {
|
|
213
|
+
activity.finish();
|
|
214
|
+
if (!isLoadAnim) {
|
|
215
|
+
activity.overridePendingTransition(0, 0);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Finish the activities whose type not equals the activity class.
|
|
223
|
+
*
|
|
224
|
+
* @param clz The activity class.
|
|
225
|
+
*/
|
|
226
|
+
public static void finishOtherActivities(@NonNull final Class<? extends Activity> clz) {
|
|
227
|
+
finishOtherActivities(clz, false);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Finish the activities whose type not equals the activity class.
|
|
232
|
+
*
|
|
233
|
+
* @param clz The activity class.
|
|
234
|
+
* @param isLoadAnim True to use animation for the outgoing activity, false otherwise.
|
|
235
|
+
*/
|
|
236
|
+
public static void finishOtherActivities(
|
|
237
|
+
@NonNull final Class<? extends Activity> clz, final boolean isLoadAnim) {
|
|
238
|
+
List<Activity> activities = getActivityList();
|
|
239
|
+
for (Activity act : activities) {
|
|
240
|
+
if (!act.getClass().equals(clz)) {
|
|
241
|
+
finishActivity(act, isLoadAnim);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public static boolean isAppForeground() {
|
|
247
|
+
ActivityManager am =
|
|
248
|
+
(ActivityManager) Utils.getApp().getSystemService(Context.ACTIVITY_SERVICE);
|
|
249
|
+
if (am == null) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
List<ActivityManager.RunningAppProcessInfo> info = am.getRunningAppProcesses();
|
|
253
|
+
if (info == null || info.size() == 0) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
for (ActivityManager.RunningAppProcessInfo aInfo : info) {
|
|
257
|
+
if (aInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
|
|
258
|
+
return aInfo.processName.equals(Utils.getApp().getPackageName());
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
static class ActivityLifecycleImpl implements ActivityLifecycleCallbacks {
|
|
265
|
+
|
|
266
|
+
final LinkedList<Activity> mActivityList = new LinkedList<>();
|
|
267
|
+
final HashMap<Object, OnAppStatusChangedListener> mStatusListenerMap = new HashMap<>();
|
|
268
|
+
|
|
269
|
+
private int mForegroundCount = 0;
|
|
270
|
+
private int mConfigCount = 0;
|
|
271
|
+
|
|
272
|
+
void addListener(final Object object, final OnAppStatusChangedListener listener) {
|
|
273
|
+
mStatusListenerMap.put(object, listener);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
void removeListener(final Object object) {
|
|
277
|
+
mStatusListenerMap.remove(object);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
@Override
|
|
281
|
+
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
|
282
|
+
setTopActivity(activity);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
@Override
|
|
286
|
+
public void onActivityStarted(Activity activity) {
|
|
287
|
+
setTopActivity(activity);
|
|
288
|
+
if (mForegroundCount <= 0) {
|
|
289
|
+
postStatus(true);
|
|
290
|
+
}
|
|
291
|
+
if (mConfigCount < 0) {
|
|
292
|
+
++mConfigCount;
|
|
293
|
+
} else {
|
|
294
|
+
++mForegroundCount;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@Override
|
|
299
|
+
public void onActivityResumed(Activity activity) {
|
|
300
|
+
setTopActivity(activity);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@Override
|
|
304
|
+
public void onActivityPaused(Activity activity) {
|
|
305
|
+
/**/
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
@Override
|
|
309
|
+
public void onActivityStopped(Activity activity) {
|
|
310
|
+
if (activity.isChangingConfigurations()) {
|
|
311
|
+
--mConfigCount;
|
|
312
|
+
} else {
|
|
313
|
+
--mForegroundCount;
|
|
314
|
+
if (mForegroundCount <= 0) {
|
|
315
|
+
postStatus(false);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
@Override
|
|
321
|
+
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
|
322
|
+
/**/
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
@Override
|
|
326
|
+
public void onActivityDestroyed(Activity activity) {
|
|
327
|
+
mActivityList.remove(activity);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private void postStatus(final boolean isForeground) {
|
|
331
|
+
if (mStatusListenerMap.isEmpty()) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
for (OnAppStatusChangedListener onAppStatusChangedListener :
|
|
335
|
+
mStatusListenerMap.values()) {
|
|
336
|
+
if (onAppStatusChangedListener == null) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (isForeground) {
|
|
340
|
+
onAppStatusChangedListener.onForeground();
|
|
341
|
+
} else {
|
|
342
|
+
onAppStatusChangedListener.onBackground();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private void setTopActivity(final Activity activity) {
|
|
348
|
+
if (activity == null || mActivityList == null) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (mActivityList.contains(activity)) {
|
|
352
|
+
Activity lastActivity = mActivityList.getLast();
|
|
353
|
+
if (lastActivity != null && !lastActivity.equals(activity)) {
|
|
354
|
+
mActivityList.remove(activity);
|
|
355
|
+
mActivityList.addLast(activity);
|
|
356
|
+
}
|
|
357
|
+
} else {
|
|
358
|
+
mActivityList.addLast(activity);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
@Nullable
|
|
363
|
+
Activity getTopActivity() {
|
|
364
|
+
if (!mActivityList.isEmpty()) {
|
|
365
|
+
final Activity topActivity = mActivityList.getLast();
|
|
366
|
+
if (topActivity != null) {
|
|
367
|
+
return topActivity;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// using reflect to get top activity
|
|
371
|
+
try {
|
|
372
|
+
@SuppressLint("PrivateApi")
|
|
373
|
+
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
|
|
374
|
+
Object activityThread =
|
|
375
|
+
activityThreadClass.getMethod("currentActivityThread").invoke(null);
|
|
376
|
+
Field activitiesField = activityThreadClass.getDeclaredField("mActivityList");
|
|
377
|
+
activitiesField.setAccessible(true);
|
|
378
|
+
Map activities = (Map) activitiesField.get(activityThread);
|
|
379
|
+
if (activities == null) {
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
for (Object activityRecord : activities.values()) {
|
|
383
|
+
Class activityRecordClass = activityRecord.getClass();
|
|
384
|
+
Field pausedField = activityRecordClass.getDeclaredField("paused");
|
|
385
|
+
pausedField.setAccessible(true);
|
|
386
|
+
if (!pausedField.getBoolean(activityRecord)) {
|
|
387
|
+
Field activityField = activityRecordClass.getDeclaredField("activity");
|
|
388
|
+
activityField.setAccessible(true);
|
|
389
|
+
Activity activity = (Activity) activityField.get(activityRecord);
|
|
390
|
+
setTopActivity(activity);
|
|
391
|
+
return activity;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
} catch (ClassNotFoundException e) {
|
|
395
|
+
e.printStackTrace();
|
|
396
|
+
} catch (IllegalAccessException e) {
|
|
397
|
+
e.printStackTrace();
|
|
398
|
+
} catch (InvocationTargetException e) {
|
|
399
|
+
e.printStackTrace();
|
|
400
|
+
} catch (NoSuchMethodException e) {
|
|
401
|
+
e.printStackTrace();
|
|
402
|
+
} catch (NoSuchFieldException e) {
|
|
403
|
+
e.printStackTrace();
|
|
404
|
+
}
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
///////////////////////////////////////////////////////////////////////////
|
|
410
|
+
// interface
|
|
411
|
+
///////////////////////////////////////////////////////////////////////////
|
|
412
|
+
|
|
413
|
+
public interface OnAppStatusChangedListener {
|
|
414
|
+
|
|
415
|
+
void onForeground();
|
|
416
|
+
|
|
417
|
+
void onBackground();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
public static int dp2px(final @NotNull Context context, final Float dpValue) {
|
|
421
|
+
final float scale = context.getResources().getDisplayMetrics().density;
|
|
422
|
+
return (int) (dpValue * scale + 0.5f);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
public static int sp2px(final @NotNull Context context, final Float sp) {
|
|
426
|
+
final float scale = context.getResources().getDisplayMetrics().scaledDensity;
|
|
427
|
+
return (int) (sp * scale + 0.5f);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
public static boolean isEmail(String email) {
|
|
431
|
+
if (null == email || "".equals(email)) return false;
|
|
432
|
+
// Pattern p = Pattern.compile("\\w+@(\\w+.)+[a-z]{2,3}"); //简单匹配
|
|
433
|
+
Pattern p = Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"); // 复杂匹配
|
|
434
|
+
Matcher m = p.matcher(email);
|
|
435
|
+
return m.matches();
|
|
436
|
+
}
|
|
437
|
+
}
|
|
Binary file
|