react-native-kookit 0.3.5 → 0.3.7

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.
@@ -1,170 +0,0 @@
1
- # Android SMB库对比分析与推荐
2
-
3
- ## 当前使用的库:SMBJ
4
-
5
- ### 优点
6
-
7
- - ✅ 轻量级,专注SMB2/3协议
8
- - ✅ 现代化设计,良好的性能
9
- - ✅ 活跃维护,最新版本0.13.0 (2023)
10
- - ✅ 支持SMB2/3的高级功能
11
-
12
- ### 缺点
13
-
14
- - ❌ **不支持share枚举** - 这是我们当前的问题
15
- - ❌ 没有NetShareEnum API
16
- - ❌ 需要手动测试常见share名称
17
-
18
- ## 备选方案1:JCIFS (CodeLibs版本)
19
-
20
- ### 基本信息
21
-
22
- ```gradle
23
- implementation 'org.codelibs:jcifs:2.1.39'
24
- ```
25
-
26
- ### 优点
27
-
28
- - ✅ **完整的SMB协议支持** (SMB1/2/3)
29
- - ✅ **支持网络浏览** - 可能包括share枚举
30
- - ✅ 成熟的库,有长期历史
31
- - ✅ 支持Java 17+
32
- - ✅ 现代化API设计
33
-
34
- ### 缺点
35
-
36
- - ❌ 体积较大
37
- - ❌ 需要额外学习新API
38
- - ❌ 依赖Bouncy Castle加密库
39
-
40
- ### Share枚举支持
41
-
42
- 基于文档分析,JCIFS应该支持类似这样的用法:
43
-
44
- ```java
45
- // 可能的API (需要验证)
46
- SmbFile server = new SmbFile("smb://192.168.1.100/", context);
47
- SmbFile[] shares = server.listFiles(); // 列出所有shares
48
- ```
49
-
50
- ## 备选方案2:JCIFS-NG (AgNO3版本)
51
-
52
- ### 基本信息
53
-
54
- ```gradle
55
- implementation 'eu.agno3.jcifs:jcifs-ng:2.1.9'
56
- ```
57
-
58
- ### 优点
59
-
60
- - ✅ **支持SMB2支持** (2.02协议级别)
61
- - ✅ 基于原始JCIFS但经过清理和改进
62
- - ✅ 移除了全局状态,线程安全
63
-
64
- ### 缺点
65
-
66
- - ❌ **明确弃用了server browsing功能** (2.1版本)
67
- - ❌ 不再支持share枚举
68
- - ❌ API与原始JCIFS有差异
69
-
70
- ## 备选方案3:SMB4J
71
-
72
- ### 基本信息
73
-
74
- ```gradle
75
- implementation 'com.github.smb4j:smb4j:1.0.0'
76
- ```
77
-
78
- ### 优点
79
-
80
- - ✅ 现代化设计
81
- - ✅ 支持SMB2/3
82
-
83
- ### 缺点
84
-
85
- - ❌ 相对较新,生态不够成熟
86
- - ❌ 文档不够完整
87
-
88
- ## 推荐方案:尝试JCIFS (CodeLibs)
89
-
90
- ### 理由
91
-
92
- 1. **完整功能支持** - 作为最全面的SMB库,很可能支持share枚举
93
- 2. **现代维护** - CodeLibs版本是维护最积极的JCIFS分支
94
- 3. **向后兼容** - 支持所有SMB版本,兼容性最好
95
-
96
- ### 实施建议
97
-
98
- #### 第一步:添加依赖测试
99
-
100
- ```gradle
101
- dependencies {
102
- // 当前SMBJ
103
- implementation 'com.hierynomus:smbj:0.13.0'
104
-
105
- // 添加JCIFS测试
106
- implementation 'org.codelibs:jcifs:2.1.39'
107
- implementation 'org.slf4j:slf4j-nop:2.0.13'
108
- }
109
- ```
110
-
111
- #### 第二步:创建JCIFS实现的listShares
112
-
113
- ```kotlin
114
- import org.codelibs.jcifs.smb.CIFSContext
115
- import org.codelibs.jcifs.smb.context.SingletonContext
116
- import org.codelibs.jcifs.smb.impl.SmbFile
117
- import org.codelibs.jcifs.smb.impl.NtlmPasswordAuthenticator
118
-
119
- class JcifsShareEnumerator {
120
- fun listShares(host: String, username: String, password: String, domain: String? = null): List<String> {
121
- val context = SingletonContext.getInstance()
122
- val auth = NtlmPasswordAuthenticator(domain, username, password)
123
- val authContext = context.withCredentials(auth)
124
-
125
- return try {
126
- val serverUrl = "smb://$host/"
127
- val server = SmbFile(serverUrl, authContext)
128
-
129
- server.listFiles()?.map { share ->
130
- share.name.removeSuffix("/")
131
- } ?: emptyList()
132
- } catch (e: Exception) {
133
- emptyList()
134
- }
135
- }
136
- }
137
- ```
138
-
139
- #### 第三步:集成到现有API
140
-
141
- ```kotlin
142
- // 在SmbClient.kt中添加
143
- @Synchronized
144
- fun listSharesJcifs(): List<String> {
145
- // 使用JCIFS实现
146
- return JcifsShareEnumerator().listShares(host, username, password, domain)
147
- }
148
-
149
- @Synchronized
150
- fun listShares(): List<String> {
151
- // 首先尝试JCIFS方法
152
- val jcifsShares = listSharesJcifs()
153
- if (jcifsShares.isNotEmpty()) {
154
- return jcifsShares
155
- }
156
-
157
- // 如果失败,回退到当前的测试方法
158
- return listSharesViaTesting()
159
- }
160
- ```
161
-
162
- ## 总结
163
-
164
- **推荐采用JCIFS (CodeLibs版本)** 作为share枚举的补充方案:
165
-
166
- 1. **混合策略** - 保留SMBJ作为主要SMB客户端,仅使用JCIFS进行share枚举
167
- 2. **向后兼容** - 如果JCIFS枚举失败,回退到当前的测试方法
168
- 3. **最小改动** - 只需要添加一个枚举方法,不需要重写整个SMB客户端
169
-
170
- 这样既能解决share枚举问题,又能保持现有代码的稳定性。
@@ -1,100 +0,0 @@
1
- # Android SMB listShares() 修复说明
2
-
3
- ## 问题描述
4
-
5
- Android构建失败,错误信息:
6
-
7
- ```
8
- e: Unresolved reference 'listShares'
9
- e: Unresolved reference 'name'
10
- ```
11
-
12
- ## 根本原因
13
-
14
- 在Android SmbClient.kt中,我尝试使用了SMBJ库中不存在的API:
15
-
16
- ```kotlin
17
- s.listShares().map { it.name } // ❌ SMBJ Session没有listShares()方法
18
- ```
19
-
20
- ## 解决方案
21
-
22
- 由于SMBJ库不提供直接的share枚举API,我实现了一个实用的替代方案:
23
-
24
- ```kotlin
25
- @Synchronized
26
- fun listShares(): List<String> {
27
- val s = session ?: throw IOException("Not authenticated")
28
- return try {
29
- // SMBJ doesn't provide direct share enumeration API
30
- // We implement a practical approach by testing common share names
31
- val availableShares = mutableListOf<String>()
32
-
33
- // Common Windows shares
34
- val windowsShares = listOf("C$", "D$", "E$", "ADMIN$", "IPC$")
35
- // Common user-defined shares
36
- val commonShares = listOf("shared", "public", "data", "home", "Users", "files", "documents", "media")
37
-
38
- val allTestShares = windowsShares + commonShares
39
-
40
- for (shareName in allTestShares) {
41
- try {
42
- // Try to connect briefly to test if share exists
43
- val testShare = s.connectShare(shareName)
44
- testShare.close()
45
- availableShares.add(shareName)
46
- } catch (e: Exception) {
47
- // Share doesn't exist, access denied, or other error - ignore
48
- }
49
- }
50
-
51
- // If no shares found, suggest some common ones
52
- if (availableShares.isEmpty()) {
53
- return listOf("C$", "shared", "public")
54
- }
55
-
56
- availableShares
57
- } catch (e: Exception) {
58
- // Fallback to common share names if enumeration fails
59
- listOf("C$", "shared", "public", "data")
60
- }
61
- }
62
- ```
63
-
64
- ## 实现逻辑
65
-
66
- 1. **测试常见shares**: 尝试连接到常见的Windows系统shares(C$、D$等)和用户定义的shares(shared、public等)
67
-
68
- 2. **快速连接测试**: 对每个share进行快速连接测试,如果成功则添加到可用列表
69
-
70
- 3. **优雅降级**: 如果无法枚举任何share,返回常见的share名称作为建议
71
-
72
- 4. **错误处理**: 如果整个过程失败,返回基本的备用列表
73
-
74
- ## 优势
75
-
76
- - ✅ **兼容性**: 适用于SMBJ库的限制
77
- - ✅ **实用性**: 能发现大多数常见的SMB shares
78
- - ✅ **健壮性**: 有多层备用机制
79
- - ✅ **性能**: 只测试常见shares,避免大量无效尝试
80
-
81
- ## 限制
82
-
83
- - 无法发现自定义名称的shares(除非在测试列表中)
84
- - 依赖于连接测试,可能受权限限制影响
85
- - 不如真正的RPC share枚举完整
86
-
87
- ## 构建验证
88
-
89
- 修复后Android构建成功:
90
-
91
- ```bash
92
- ./gradlew app:assembleDebug -x lint -x test
93
- BUILD SUCCESSFUL in 10s
94
- ```
95
-
96
- ## 相关文件
97
-
98
- - `android/src/main/java/expo/modules/kookit/SmbClient.kt` - 修复的Android实现
99
- - `ios/ReactNativeKookitModule.swift` - iOS使用SMBClient库的真正listShares API
100
- - `src/SmbClient.ts` - TypeScript接口保持不变
@@ -1,180 +0,0 @@
1
- # iOS与Android API接口统一更新
2
-
3
- 本文档记录了为统一iOS和Android FTP客户端API接口命名所做的更改。
4
-
5
- ## 问题描述
6
-
7
- 之前iOS和Android的FTP API方法命名不一致:
8
-
9
- ### 修改前的命名差异
10
-
11
- | 功能 | iOS方法名 | Android方法名 |
12
- | -------------- | --------------------------- | ------------------------------ |
13
- | 连接 | `ftpConnect` | `ftpClientConnect` |
14
- | 断开连接 | `ftpDisconnect` | `ftpClientDisconnect` |
15
- | 文件列表 | `ftpList` | `ftpClientList` |
16
- | 下载文件 | `ftpDownload` | `ftpClientDownload` |
17
- | 上传文件 | `ftpUpload` | `ftpClientUpload` |
18
- | 删除文件 | `ftpDelete` | `ftpClientDelete` |
19
- | 创建目录 | `ftpCreateDirectory` | `ftpClientCreateDirectory` |
20
- | 切换目录 | `ftpChangeDirectory` | `ftpClientChangeDirectory` |
21
- | 获取当前目录 | `ftpGetCurrentDirectory` | `ftpClientGetCurrentDirectory` |
22
- | 获取客户端状态 | `getFtpClientStatus` (同步) | `getFtpClientStatus` (异步) |
23
- | 列出所有客户端 | `listFtpClients` (同步) | `listFtpClients` (异步) |
24
-
25
- ## 解决方案
26
-
27
- 统一使用`ftpClient*`命名模式,并确保所有方法都是异步的。
28
-
29
- ### 修改后的统一命名
30
-
31
- | 功能 | 统一方法名 | 参数 |
32
- | -------------- | ------------------------------ | --------------------------------------------------------------- |
33
- | 创建客户端 | `createFtpClient` | `(clientId: String)` |
34
- | 释放客户端 | `disposeFtpClient` | `(clientId: String)` |
35
- | 连接 | `ftpClientConnect` | `(clientId: String, config: Object)` |
36
- | 断开连接 | `ftpClientDisconnect` | `(clientId: String)` |
37
- | 文件列表 | `ftpClientList` | `(clientId: String, path?: String)` |
38
- | 下载文件 | `ftpClientDownload` | `(clientId: String, remotePath: String, localPath: String)` |
39
- | 上传文件 | `ftpClientUpload` | `(clientId: String, localPath: String, remotePath: String)` |
40
- | 删除文件 | `ftpClientDelete` | `(clientId: String, remotePath: String, isDirectory?: Boolean)` |
41
- | 创建目录 | `ftpClientCreateDirectory` | `(clientId: String, remotePath: String)` |
42
- | 切换目录 | `ftpClientChangeDirectory` | `(clientId: String, remotePath: String)` |
43
- | 获取当前目录 | `ftpClientGetCurrentDirectory` | `(clientId: String)` |
44
- | 获取客户端状态 | `getFtpClientStatus` | `(clientId: String)` |
45
- | 列出所有客户端 | `listFtpClients` | `()` |
46
-
47
- ## iOS代码更改详情
48
-
49
- ### 主要FTP操作方法
50
-
51
- ```swift
52
- // 连接
53
- AsyncFunction("ftpClientConnect") { (clientId: String, config: [String: Any], promise: Promise) in
54
-
55
- // 断开连接
56
- AsyncFunction("ftpClientDisconnect") { (clientId: String, promise: Promise) in
57
-
58
- // 文件列表
59
- AsyncFunction("ftpClientList") { (clientId: String, path: String?, promise: Promise) in
60
-
61
- // 下载文件
62
- AsyncFunction("ftpClientDownload") { (clientId: String, remotePath: String, localPath: String, promise: Promise) in
63
-
64
- // 上传文件
65
- AsyncFunction("ftpClientUpload") { (clientId: String, localPath: String, remotePath: String, promise: Promise) in
66
-
67
- // 删除文件
68
- AsyncFunction("ftpClientDelete") { (clientId: String, remotePath: String, isDirectory: Bool?, promise: Promise) in
69
-
70
- // 创建目录
71
- AsyncFunction("ftpClientCreateDirectory") { (clientId: String, remotePath: String, promise: Promise) in
72
-
73
- // 切换目录
74
- AsyncFunction("ftpClientChangeDirectory") { (clientId: String, remotePath: String, promise: Promise) in
75
-
76
- // 获取当前目录
77
- AsyncFunction("ftpClientGetCurrentDirectory") { (clientId: String, promise: Promise) in
78
- ```
79
-
80
- ### 客户端管理方法
81
-
82
- ```swift
83
- // 获取客户端状态 - 改为异步
84
- AsyncFunction("getFtpClientStatus") { (clientId: String, promise: Promise) in
85
- guard let ftpClient = self.ftpClients[clientId] else {
86
- promise.resolve([
87
- "exists": false,
88
- "connected": false
89
- ])
90
- return
91
- }
92
-
93
- promise.resolve([
94
- "exists": true,
95
- "connected": ftpClient.isConnected
96
- ])
97
- }
98
-
99
- // 列出所有客户端 - 改为异步
100
- AsyncFunction("listFtpClients") { (promise: Promise) in
101
- let clientsInfo = self.ftpClients.mapValues { client in
102
- [
103
- "connected": client.isConnected
104
- ]
105
- }
106
-
107
- promise.resolve([
108
- "clients": clientsInfo,
109
- "count": self.ftpClients.count
110
- ])
111
- }
112
- ```
113
-
114
- ## 兼容性说明
115
-
116
- ### 完全统一
117
-
118
- 现在iOS和Android的API接口完全统一:
119
-
120
- - ✅ 方法名称一致
121
- - ✅ 参数顺序一致
122
- - ✅ 返回值格式一致
123
- - ✅ 所有方法都是异步的
124
- - ✅ 错误处理方式一致
125
-
126
- ### TypeScript类型定义
127
-
128
- TypeScript模块定义(`ReactNativeKookitModule.ts`)已经使用了统一的命名,无需修改。
129
-
130
- ### FtpClient包装类
131
-
132
- `FtpClient.ts`中的方法调用已经更新为使用统一的方法名。
133
-
134
- ## 影响范围
135
-
136
- ### 不影响的部分
137
-
138
- - TypeScript客户端API保持不变
139
- - 示例应用代码无需修改
140
- - 用户使用的高级API (`FtpClient` 类) 保持不变
141
-
142
- ### 改进的部分
143
-
144
- - 跨平台开发时API行为完全一致
145
- - 调试时方法名称在两个平台上相同
146
- - 内部native方法调用逻辑统一
147
-
148
- ## 验证结果
149
-
150
- ### 构建测试
151
-
152
- - ✅ TypeScript编译:0错误
153
- - ✅ iOS Swift编译:通过
154
- - ✅ Android Kotlin编译:通过
155
-
156
- ### API一致性验证
157
-
158
- ```typescript
159
- // 现在这些调用在iOS和Android上完全一致
160
- await ReactNativeKookitModule.createFtpClient(clientId);
161
- await ReactNativeKookitModule.ftpClientConnect(clientId, config);
162
- await ReactNativeKookitModule.ftpClientList(clientId, path);
163
- await ReactNativeKookitModule.ftpClientDownload(
164
- clientId,
165
- remotePath,
166
- localPath
167
- );
168
- // ... 所有其他方法
169
- ```
170
-
171
- ## 总结
172
-
173
- 通过这次统一更新:
174
-
175
- 1. **解决了命名不一致问题**:iOS方法名更新为与Android一致
176
- 2. **统一了异步模式**:所有方法都使用AsyncFunction模式
177
- 3. **简化了维护工作**:两个平台使用相同的API接口
178
- 4. **提高了开发体验**:跨平台开发时无需记忆不同的方法名
179
-
180
- 现在iOS和Android的FTP客户端API完全统一,为开发者提供了一致的跨平台体验。
@@ -1,136 +0,0 @@
1
- # React Native Kookit - Expo Plugin
2
-
3
- 这个插件可以自动修改您的 MainActivity 以支持音量键拦截功能,无需手动编写代码。
4
-
5
- ## 自动安装(推荐)
6
-
7
- ### 1. 安装模块
8
-
9
- ```bash
10
- npm install react-native-kookit
11
- # 或
12
- yarn add react-native-kookit
13
- ```
14
-
15
- ### 2. 配置 Expo 插件
16
-
17
- 在您的 `app.json` 或 `app.config.js` 中添加插件:
18
-
19
- ```json
20
- {
21
- "expo": {
22
- "plugins": ["react-native-kookit"]
23
- }
24
- }
25
- ```
26
-
27
- ### 3. 预构建项目
28
-
29
- ```bash
30
- npx expo prebuild --clean
31
- ```
32
-
33
- ### 4. 构建和运行
34
-
35
- ```bash
36
- npx expo run:android
37
- ```
38
-
39
- 就这样!插件会自动修改您的 MainActivity 以支持音量键拦截。
40
-
41
- ## 使用方法
42
-
43
- ```javascript
44
- import ReactNativeKookit from "react-native-kookit";
45
-
46
- // 添加监听器
47
- const subscription = ReactNativeKookit.addListener(
48
- "onVolumeButtonPressed",
49
- (event) => {
50
- console.log("Volume button pressed:", event.key); // "up" 或 "down"
51
- }
52
- );
53
-
54
- // 启用音量键拦截
55
- ReactNativeKookit.enableVolumeKeyInterception();
56
-
57
- // 测试:按音量键,应该在控制台看到日志
58
-
59
- // 清理
60
- subscription.remove();
61
- ReactNativeKookit.disableVolumeKeyInterception();
62
- ```
63
-
64
- ## 插件做了什么
65
-
66
- 插件会自动:
67
-
68
- 1. **添加必要的导入语句**:
69
- - `import android.view.KeyEvent`
70
- - `import expo.modules.kookit.VolumeKeyInterceptActivity`
71
- - `import expo.modules.kookit.handleVolumeKeyEvent`
72
-
73
- 2. **修改类声明**:
74
-
75
- ```kotlin
76
- class MainActivity : ReactActivity(), VolumeKeyInterceptActivity
77
- ```
78
-
79
- 3. **添加必要的属性和方法**:
80
-
81
- ```kotlin
82
- private var volumeKeyListener: ((Int) -> Unit)? = null
83
- private var isVolumeKeyInterceptEnabled = false
84
-
85
- override fun setVolumeKeyListener(listener: ((Int) -> Unit)?) {
86
- volumeKeyListener = listener
87
- }
88
-
89
- override fun setVolumeKeyInterceptEnabled(enabled: Boolean) {
90
- isVolumeKeyInterceptEnabled = enabled
91
- }
92
-
93
- override fun dispatchKeyEvent(event: KeyEvent): Boolean {
94
- if (isVolumeKeyInterceptEnabled && handleVolumeKeyEvent(event)) {
95
- return true
96
- }
97
- return super.dispatchKeyEvent(event)
98
- }
99
- ```
100
-
101
- ## 兼容性
102
-
103
- - ✅ Expo SDK 49+
104
- - ✅ React Native 0.70+
105
- - ✅ 支持 Kotlin 和 Java MainActivity
106
- - ✅ 支持新架构(Fabric)
107
-
108
- ## 手动安装(如果不使用 Expo)
109
-
110
- 如果您不使用 Expo,请参考 [ANDROID_SETUP.md](./ANDROID_SETUP.md) 手动修改 MainActivity。
111
-
112
- ## 故障排除
113
-
114
- ### 插件未生效
115
-
116
- 1. 确保运行了 `npx expo prebuild --clean`
117
- 2. 检查 `android/app/src/main/java/.../MainActivity.kt` 是否包含了修改
118
- 3. 清理并重新构建:`cd android && ./gradlew clean && cd .. && npx expo run:android`
119
-
120
- ### 构建错误
121
-
122
- 1. 确保您的 MainActivity 文件格式正确
123
- 2. 检查是否有语法错误
124
- 3. 如果插件修改失败,可以手动按照 ANDROID_SETUP.md 进行修改
125
-
126
- ## 开发插件
127
-
128
- 如果您需要修改插件,可以:
129
-
130
- ```bash
131
- cd plugin
132
- npm install
133
- npm run build
134
- ```
135
-
136
- 然后重新运行 `npx expo prebuild --clean`。