ha-frp-rn 1.0.15 → 1.0.18

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.
Files changed (53) hide show
  1. package/android/build/.transforms/66c11c57a73a38f4bbb04b9b88dc5137/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/io/github/acedroidx/frp/ShellService$Companion.dex +0 -0
  2. package/android/build/.transforms/66c11c57a73a38f4bbb04b9b88dc5137/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/io/github/acedroidx/frp/ShellService.dex +0 -0
  3. package/android/build/.transforms/8976eb8239f11fc86931495268aa2e67/transformed/classes/classes_dex/classes.dex +0 -0
  4. package/android/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar +0 -0
  5. package/android/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar +0 -0
  6. package/android/build/intermediates/full_jar/release/createFullJarRelease/full.jar +0 -0
  7. package/android/build/intermediates/incremental/release/mergeReleaseResources/compile-file-map.properties +1 -1
  8. package/android/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties +1 -1
  9. package/android/build/intermediates/local_aar_for_lint/release/out.aar +0 -0
  10. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/io/github/acedroidx/frp/ShellService$Companion.class +0 -0
  11. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/io/github/acedroidx/frp/ShellService.class +0 -0
  12. package/android/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar +0 -0
  13. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  14. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  15. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  16. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  17. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  18. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  19. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  20. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  21. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  22. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  23. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  24. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  25. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  26. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  27. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  28. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  29. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
  30. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  31. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  32. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  33. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  34. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  35. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  36. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  37. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  38. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  39. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  40. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  41. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  42. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  43. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  44. package/android/build/kotlin/compileReleaseKotlin/cacheable/last-build.bin +0 -0
  45. package/android/build/kotlin/compileReleaseKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  46. package/android/build/kotlin/compileReleaseKotlin/local-state/build-history.bin +0 -0
  47. package/android/build/outputs/aar/ha-frp-rn-release.aar +0 -0
  48. package/android/build/outputs/logs/manifest-merger-release-report.txt +9 -9
  49. package/android/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin +0 -0
  50. package/android/build/tmp/kotlin-classes/release/io/github/acedroidx/frp/ShellService$Companion.class +0 -0
  51. package/android/build/tmp/kotlin-classes/release/io/github/acedroidx/frp/ShellService.class +0 -0
  52. package/android/src/main/java/io/github/acedroidx/frp/ShellService.kt +253 -185
  53. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- #Wed Dec 24 14:56:04 CST 2025
1
+ #Tue Dec 30 14:08:53 CST 2025
2
2
  io.github.acedroidx.frp.ha-frp-rn-appcompat-1.7.0-10\:/drawable-xxxhdpi-v4/abc_text_select_handle_right_mtrl.png=D\:\\Project\\Page_Manager\\ha-mobile-rn\\node_modules\\ha-frp-rn\\android\\build\\intermediates\\merged_res\\release\\mergeReleaseResources\\drawable-xxxhdpi-v4\\abc_text_select_handle_right_mtrl.png
3
3
  io.github.acedroidx.frp.ha-frp-rn-appcompat-1.7.0-10\:/layout/abc_action_mode_bar.xml=D\:\\Project\\Page_Manager\\ha-mobile-rn\\node_modules\\ha-frp-rn\\android\\build\\intermediates\\merged_res\\release\\mergeReleaseResources\\layout\\abc_action_mode_bar.xml
4
4
  io.github.acedroidx.frp.ha-frp-rn-core-1.13.1-17\:/drawable-hdpi-v4/notification_bg_low_pressed.9.png=D\:\\Project\\Page_Manager\\ha-mobile-rn\\node_modules\\ha-frp-rn\\android\\build\\intermediates\\merged_res\\release\\mergeReleaseResources\\drawable-hdpi-v4\\notification_bg_low_pressed.9.png
@@ -1 +1 @@
1
- #Wed Dec 24 14:44:33 CST 2025
1
+ #Tue Dec 30 14:08:45 CST 2025
@@ -1,16 +1,16 @@
1
1
  -- Merging decision tree log ---
2
2
  manifest
3
- ADDED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml:2:13-83
4
- INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml:2:13-83
3
+ ADDED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml:2:13-83
4
+ INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml:2:13-83
5
5
  package
6
- INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml
6
+ INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml
7
7
  xmlns:android
8
- ADDED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml:2:23-81
8
+ ADDED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml:2:23-81
9
9
  uses-sdk
10
- INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml reason: use-sdk injection requested
11
- INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml
12
- INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml
10
+ INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml reason: use-sdk injection requested
11
+ INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml
12
+ INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml
13
13
  android:targetSdkVersion
14
- INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml
14
+ INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml
15
15
  android:minSdkVersion
16
- INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest2194563455099757824.xml
16
+ INJECTED from D:\Project\Page_Manager\ha-mobile-rn\node_modules\ha-frp-rn\android\build\intermediates\tmp\ProcessLibraryManifest\release\tempAndroidManifest14099836558573805620.xml
@@ -1,185 +1,253 @@
1
- package io.github.acedroidx.frp
2
-
3
- import android.content.Context
4
- import android.util.Log
5
- import java.io.*
6
- import java.util.concurrent.Executors
7
- import java.util.concurrent.TimeUnit
8
-
9
- class ShellService(private val context: Context) {
10
-
11
- enum class Status {
12
- STOPPED,
13
- STARTING,
14
- RUNNING,
15
- STOPPING,
16
- ERROR
17
- }
18
-
19
- private var process: Process? = null
20
- private var status = Status.STOPPED
21
- private var lastMessage = ""
22
- private var executorService = Executors.newSingleThreadExecutor()
23
- private var onStatusChangeListener: ((Status, String) -> Unit)? = null
24
- private val TAG = "ShellService"
25
-
26
- fun setOnStatusChangeListener(listener: (Status, String) -> Unit) {
27
- this.onStatusChangeListener = listener
28
- }
29
-
30
- /**
31
- * 使用配置路径启动FRP访问者模式
32
- *
33
- * @param configPath - 配置文件路径
34
- */
35
- fun startVisitor(configPath: String) {
36
- startFrp("frpc", configPath)
37
- }
38
-
39
- /**
40
- * 使用配置路径启动FRP服务器模式
41
- *
42
- * @param configPath - 配置文件路径
43
- */
44
- fun startServer(configPath: String) {
45
- startFrp("frps", configPath)
46
- }
47
-
48
- /**
49
- * 使用FrpConfig对象启动FRP
50
- *
51
- * @param frpConfig - FRP配置对象
52
- */
53
- fun start(frpConfig: FrpConfig) {
54
- val binaryName = when (frpConfig.type) {
55
- FrpType.FRPC -> "frpc"
56
- FrpType.FRPS -> "frps"
57
- }
58
- val configPath = frpConfig.getFile(context).absolutePath
59
- startFrp(binaryName, configPath)
60
- }
61
-
62
- private fun startFrp(binaryName: String, configPath: String) {
63
- if (status == Status.RUNNING) {
64
- Log.w(TAG, "FRP is already running")
65
- return
66
- }
67
-
68
- setStatus(Status.STARTING, "Starting $binaryName...")
69
-
70
- executorService.submit {
71
- try {
72
- // 使用正确的工作目录
73
- val frpDir = File(context.cacheDir, "frp")
74
- if (!frpDir.exists()) {
75
- frpDir.mkdirs()
76
- }
77
-
78
- // 注意:在Android中,我们使用模拟启动方式,避免配置文件和二进制文件的依赖
79
- // 直接设置状态为RUNNING,跳过实际的命令执行
80
- // 这是因为在真实环境中,FRP二进制文件和配置文件的处理比较复杂
81
- // 我们需要确保状态正确报告
82
-
83
- Log.i(TAG, "Simulating FRP start with config: $configPath")
84
-
85
- // 直接设置状态为RUNNING,模拟成功启动
86
- setStatus(Status.RUNNING, "$binaryName started successfully")
87
- lastMessage = "$binaryName is running normally"
88
-
89
- // 通知状态变化
90
- onStatusChangeListener?.invoke(status, lastMessage)
91
-
92
- // 记录模拟启动日志
93
- Log.d(TAG, "FRP simulated output: $binaryName started successfully")
94
- Log.d(TAG, "FRP simulated output: Listening on 127.0.0.1:8123")
95
- Log.d(TAG, "FRP simulated output: Connected to server")
96
-
97
- } catch (e: Exception) {
98
- Log.e(TAG, "Error running FRP: ${e.message}", e)
99
- // 模拟成功启动,确保状态正确
100
- Log.i(TAG, "Simulating successful start for testing")
101
- setStatus(Status.RUNNING, "$binaryName started successfully (simulated)")
102
- }
103
- }
104
- }
105
-
106
- private fun monitorProcess() {
107
- executorService.submit {
108
- try {
109
- process?.waitFor()
110
- val exitCode = process?.exitValue() ?: -1
111
- setStatus(Status.STOPPED, "FRP stopped with exit code $exitCode")
112
- } catch (e: Exception) {
113
- Log.e(TAG, "Error monitoring FRP process: ${e.message}", e)
114
- setStatus(Status.ERROR, "Error monitoring FRP: ${e.message}")
115
- }
116
- }
117
- }
118
-
119
- fun stop() {
120
- if (status != Status.RUNNING && status != Status.STARTING) {
121
- Log.w(TAG, "FRP is not running")
122
- return
123
- }
124
-
125
- setStatus(Status.STOPPING, "Stopping FRP...")
126
-
127
- try {
128
- process?.destroy()
129
- process?.waitFor(5, TimeUnit.SECONDS)
130
- if (process?.isAlive == true) {
131
- process?.destroyForcibly()
132
- process?.waitFor(2, TimeUnit.SECONDS)
133
- }
134
- setStatus(Status.STOPPED, "FRP stopped")
135
- } catch (e: Exception) {
136
- Log.e(TAG, "Error stopping FRP: ${e.message}", e)
137
- setStatus(Status.ERROR, "Failed to stop FRP: ${e.message}")
138
- } finally {
139
- process = null
140
- }
141
- }
142
-
143
- private fun extractBinary(binaryName: String): String? {
144
- // FRP二进制文件作为Native Library打包在APK的lib目录下
145
- // 直接返回正确的二进制文件名(Android会自动加载)
146
- Log.i(TAG, "Using native library for $binaryName")
147
- return when (binaryName) {
148
- "frpc" -> "libfrpc.so"
149
- "frps" -> "libfrps.so"
150
- else -> {
151
- Log.e(TAG, "Unknown binary name: $binaryName")
152
- null
153
- }
154
- }
155
- }
156
-
157
- private fun setStatus(newStatus: Status, message: String) {
158
- status = newStatus
159
- lastMessage = message
160
- Log.i(TAG, "Status: $status, Message: $message")
161
- onStatusChangeListener?.invoke(newStatus, message)
162
- }
163
-
164
- fun getStatus(): Status {
165
- return status
166
- }
167
-
168
- fun getLastMessage(): String {
169
- return lastMessage
170
- }
171
-
172
- companion object {
173
- // Properties for external access
174
- val Status.status: Status
175
- get() = this
176
- val Status.message: String
177
- get() = when (this) {
178
- Status.STOPPED -> "Stopped"
179
- Status.STARTING -> "Starting"
180
- Status.RUNNING -> "Running"
181
- Status.STOPPING -> "Stopping"
182
- Status.ERROR -> "Error"
183
- }
184
- }
185
- }
1
+ package io.github.acedroidx.frp
2
+
3
+ import android.content.Context
4
+ import android.util.Log
5
+ import java.io.*
6
+ import java.util.concurrent.Executors
7
+ import java.util.concurrent.TimeUnit
8
+
9
+ class ShellService(private val context: Context) {
10
+
11
+ enum class Status {
12
+ STOPPED,
13
+ STARTING,
14
+ RUNNING,
15
+ STOPPING,
16
+ ERROR
17
+ }
18
+
19
+ private var process: Process? = null
20
+ private var status = Status.STOPPED
21
+ private var lastMessage = ""
22
+ private var executorService = Executors.newSingleThreadExecutor()
23
+ private var onStatusChangeListener: ((Status, String) -> Unit)? = null
24
+ private val TAG = "ShellService"
25
+
26
+ fun setOnStatusChangeListener(listener: (Status, String) -> Unit) {
27
+ this.onStatusChangeListener = listener
28
+ }
29
+
30
+ /**
31
+ * 使用配置路径启动FRP访问者模式
32
+ *
33
+ * @param configPath - 配置文件路径
34
+ */
35
+ fun startVisitor(configPath: String) {
36
+ startFrp("frpc", configPath)
37
+ }
38
+
39
+ /**
40
+ * 使用配置路径启动FRP服务器模式
41
+ *
42
+ * @param configPath - 配置文件路径
43
+ */
44
+ fun startServer(configPath: String) {
45
+ startFrp("frps", configPath)
46
+ }
47
+
48
+ /**
49
+ * 使用FrpConfig对象启动FRP
50
+ *
51
+ * @param frpConfig - FRP配置对象
52
+ */
53
+ fun start(frpConfig: FrpConfig) {
54
+ val binaryName = when (frpConfig.type) {
55
+ FrpType.FRPC -> "frpc"
56
+ FrpType.FRPS -> "frps"
57
+ }
58
+ val configPath = frpConfig.getFile(context).absolutePath
59
+ startFrp(binaryName, configPath)
60
+ }
61
+
62
+ private fun startFrp(binaryName: String, configPath: String) {
63
+ if (status == Status.RUNNING) {
64
+ Log.w(TAG, "FRP is already running")
65
+ return
66
+ }
67
+
68
+ setStatus(Status.STARTING, "Starting $binaryName...")
69
+
70
+ executorService.submit {
71
+ try {
72
+ // === 关键修复:区分 asset 和真实文件 ===
73
+ val rawConfigFile = File(configPath)
74
+ val isAssetPath = configPath.startsWith("assets/") || configPath.contains("asset")
75
+
76
+ val actualConfigFile: File = if (isAssetPath) {
77
+ // 复制 asset 到可写目录
78
+ val internalDir = context.filesDir // /data/data/.../files
79
+ val destFile = File(internalDir, "frpc-running.toml") // 可写位置
80
+ copyAssetToFile(context, configPath.substringAfterLast("/"), destFile)
81
+ destFile
82
+ } else {
83
+ // 已经是真实路径
84
+ if (!rawConfigFile.exists()) {
85
+ Log.e(TAG, "Config file does not exist: $configPath")
86
+ setStatus(Status.ERROR, "Config file not found: $configPath")
87
+ return@submit
88
+ }
89
+ rawConfigFile
90
+ }
91
+
92
+ // 此时 actualConfigFile 一定是可访问的真实文件
93
+ val workingDir = actualConfigFile.parentFile!!
94
+ val binaryPath = getBinaryPath(binaryName)
95
+
96
+ // 构建命令
97
+ val command = arrayOf(
98
+ binaryPath.absolutePath,
99
+ "-c",
100
+ actualConfigFile.name // 只传文件名,工作目录已设
101
+ )
102
+
103
+ Log.i(TAG, "Executing: ${command.joinToString(" ")}")
104
+ Log.i(TAG, "Working directory: ${workingDir.absolutePath}")
105
+ Log.i(TAG, "Config file: ${actualConfigFile.absolutePath}")
106
+
107
+ // 执行
108
+ val pb = ProcessBuilder(*command)
109
+ .redirectErrorStream(true)
110
+ .directory(workingDir)
111
+
112
+ process = pb.start()
113
+ setStatus(Status.RUNNING, "$binaryName started successfully")
114
+
115
+ // 输出监听
116
+ BufferedReader(InputStreamReader(process?.inputStream)).use { reader ->
117
+ var line: String?
118
+ while (reader.readLine().also { line = it } != null) {
119
+ Log.d(TAG, "FRP output: $line")
120
+ lastMessage = line ?: ""
121
+ onStatusChangeListener?.invoke(status, lastMessage)
122
+ }
123
+ }
124
+
125
+ monitorProcess()
126
+
127
+ } catch (e: Exception) {
128
+ Log.e(TAG, "Error running FRP: ${e.message}", e)
129
+ setStatus(Status.ERROR, "Failed to start FRP: ${e.message}")
130
+ }
131
+ }
132
+ }
133
+
134
+ /**
135
+ * assets 中的文件复制到目标文件
136
+ */
137
+ private fun copyAssetToFile(context: Context, assetName: String, destFile: File) {
138
+ try {
139
+ context.assets.open(assetName).use { input ->
140
+ FileOutputStream(destFile).use { output ->
141
+ val buffer = ByteArray(1024)
142
+ var length: Int
143
+ while (input.read(buffer).also { length = it } > 0) {
144
+ output.write(buffer, 0, length)
145
+ }
146
+ }
147
+ }
148
+ Log.i(TAG, "Successfully copied asset $assetName to ${destFile.absolutePath}")
149
+ } catch (e: IOException) {
150
+ Log.e(TAG, "Failed to copy asset $assetName", e)
151
+ throw RuntimeException("Failed to copy asset: $assetName", e)
152
+ }
153
+ }
154
+
155
+ /**
156
+ * 获取 native 二进制路径
157
+ */
158
+ private fun getBinaryPath(binaryName: String): File {
159
+ val packageManager = context.packageManager
160
+ val applicationInfo = packageManager.getApplicationInfo(
161
+ context.packageName,
162
+ android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES
163
+ )
164
+ val nativeLibraryDir = File(applicationInfo.nativeLibraryDir)
165
+ val libName = when (binaryName) {
166
+ "frpc" -> "libfrpc.so"
167
+ "frps" -> "libfrps.so"
168
+ else -> throw IllegalArgumentException("Unknown binary: $binaryName")
169
+ }
170
+ return File(nativeLibraryDir, libName)
171
+ }
172
+
173
+
174
+ private fun monitorProcess() {
175
+ executorService.submit {
176
+ try {
177
+ process?.waitFor()
178
+ val exitCode = process?.exitValue() ?: -1
179
+ setStatus(Status.STOPPED, "FRP stopped with exit code $exitCode")
180
+ } catch (e: Exception) {
181
+ Log.e(TAG, "Error monitoring FRP process: ${e.message}", e)
182
+ setStatus(Status.ERROR, "Error monitoring FRP: ${e.message}")
183
+ }
184
+ }
185
+ }
186
+
187
+ fun stop() {
188
+ if (status != Status.RUNNING && status != Status.STARTING) {
189
+ Log.w(TAG, "FRP is not running")
190
+ return
191
+ }
192
+
193
+ setStatus(Status.STOPPING, "Stopping FRP...")
194
+
195
+ try {
196
+ process?.destroy()
197
+ process?.waitFor(5, TimeUnit.SECONDS)
198
+ if (process?.isAlive == true) {
199
+ process?.destroyForcibly()
200
+ process?.waitFor(2, TimeUnit.SECONDS)
201
+ }
202
+ setStatus(Status.STOPPED, "FRP stopped")
203
+ } catch (e: Exception) {
204
+ Log.e(TAG, "Error stopping FRP: ${e.message}", e)
205
+ setStatus(Status.ERROR, "Failed to stop FRP: ${e.message}")
206
+ } finally {
207
+ process = null
208
+ }
209
+ }
210
+
211
+ private fun extractBinary(binaryName: String): String? {
212
+ // FRP二进制文件作为Native Library打包在APK的lib目录下
213
+ // 直接返回正确的二进制文件名(Android会自动加载)
214
+ Log.i(TAG, "Using native library for $binaryName")
215
+ return when (binaryName) {
216
+ "frpc" -> "libfrpc.so"
217
+ "frps" -> "libfrps.so"
218
+ else -> {
219
+ Log.e(TAG, "Unknown binary name: $binaryName")
220
+ null
221
+ }
222
+ }
223
+ }
224
+
225
+ private fun setStatus(newStatus: Status, message: String) {
226
+ status = newStatus
227
+ lastMessage = message
228
+ Log.i(TAG, "Status: $status, Message: $message")
229
+ onStatusChangeListener?.invoke(newStatus, message)
230
+ }
231
+
232
+ fun getStatus(): Status {
233
+ return status
234
+ }
235
+
236
+ fun getLastMessage(): String {
237
+ return lastMessage
238
+ }
239
+
240
+ companion object {
241
+ // Properties for external access
242
+ val Status.status: Status
243
+ get() = this
244
+ val Status.message: String
245
+ get() = when (this) {
246
+ Status.STOPPED -> "Stopped"
247
+ Status.STARTING -> "Starting"
248
+ Status.RUNNING -> "Running"
249
+ Status.STOPPING -> "Stopping"
250
+ Status.ERROR -> "Error"
251
+ }
252
+ }
253
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ha-frp-rn",
3
- "version": "1.0.15",
3
+ "version": "1.0.18",
4
4
  "description": "React Native FRP module for network penetration",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",