react-native-kookit 0.3.5 → 0.3.6
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/CHANGELOG_CONTENT_URI.md +130 -0
- package/IMPLEMENTATION_SUMMARY.md +206 -0
- package/README.md +21 -1
- package/android/src/main/java/expo/modules/kookit/ReactNativeKookitModule.kt +139 -0
- package/build/ReactNativeKookitModule.d.ts +28 -0
- package/build/ReactNativeKookitModule.d.ts.map +1 -1
- package/build/ReactNativeKookitModule.js.map +1 -1
- package/package.json +1 -1
- package/ANDROID_BUILD_FIX.md +0 -117
- package/ANDROID_FTP_UPDATE.md +0 -161
- package/ANDROID_PARAMETER_FIX.md +0 -0
- package/ANDROID_SETUP.md +0 -188
- package/ANDROID_SMB_LIBRARY_COMPARISON.md +0 -170
- package/ANDROID_SMB_LISTSHARES_FIX.md +0 -100
- package/API_UNIFICATION.md +0 -180
- package/EXPO_PLUGIN_README.md +0 -136
- package/FTP_CLIENT_API.md +0 -301
- package/FTP_EXAMPLE_IMPLEMENTATION.md +0 -0
- package/FTP_FILE_LIST_ENHANCEMENT.md +0 -186
- package/FTP_FILE_OPERATIONS.md +0 -0
- package/FTP_README.md +0 -322
- package/README_NEW.md +0 -143
- package/RELEASE_CHECKLIST.md +0 -115
- package/SMB_CLIENT_STATIC_METHODS.md +0 -175
- package/SMB_COMPLETE_GUIDE.md +0 -308
- package/SMB_HYBRID_IMPLEMENTATION.md +0 -160
- package/SMB_IMPLEMENTATION_SUMMARY.md +0 -229
- package/SMB_USAGE.md +0 -275
- package/TROUBLESHOOTING.md +0 -132
package/ANDROID_BUILD_FIX.md
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# Android 构建修复总结
|
|
2
|
-
|
|
3
|
-
## 问题诊断与解决
|
|
4
|
-
|
|
5
|
-
### 遇到的问题
|
|
6
|
-
|
|
7
|
-
Android 构建失败,主要错误包括:
|
|
8
|
-
|
|
9
|
-
1. `Unresolved reference 'SMB2CreateDisposition'`
|
|
10
|
-
2. `Unresolved reference 'SMB2ShareAccess'`
|
|
11
|
-
3. `Unresolved reference 'isDirectory'`
|
|
12
|
-
4. `Unresolved reference 'msftyp'`
|
|
13
|
-
5. `FileAttributes.contains()` 方法使用错误
|
|
14
|
-
|
|
15
|
-
### 解决方案
|
|
16
|
-
|
|
17
|
-
#### 1. 修正 SMBJ 库的 import 包名
|
|
18
|
-
|
|
19
|
-
```kotlin
|
|
20
|
-
// 修正前 (错误)
|
|
21
|
-
import com.hierynomus.msfscc.SMB2CreateDisposition
|
|
22
|
-
import com.hierynomus.msfscc.SMB2ShareAccess
|
|
23
|
-
|
|
24
|
-
// 修正后 (正确)
|
|
25
|
-
import com.hierynomus.mssmb2.SMB2CreateDisposition
|
|
26
|
-
import com.hierynomus.mssmb2.SMB2ShareAccess
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
#### 2. 移除不存在的包
|
|
30
|
-
|
|
31
|
-
```kotlin
|
|
32
|
-
// 移除了这个不存在的 import
|
|
33
|
-
import com.hierynomus.msftyp.FileInformationClass
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
#### 3. 修正 FileAttributes 的目录检查方式
|
|
37
|
-
|
|
38
|
-
```kotlin
|
|
39
|
-
// 修正前 (错误)
|
|
40
|
-
val isDir = info.fileAttributes.contains(FileAttributes.FILE_ATTRIBUTE_DIRECTORY)
|
|
41
|
-
|
|
42
|
-
// 修正后 (正确)
|
|
43
|
-
val isDir = info.fileAttributes and FileAttributes.FILE_ATTRIBUTE_DIRECTORY.value != 0L
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### 最终的正确 import 语句
|
|
47
|
-
|
|
48
|
-
```kotlin
|
|
49
|
-
package expo.modules.kookit
|
|
50
|
-
|
|
51
|
-
import com.hierynomus.msdtyp.AccessMask
|
|
52
|
-
import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation
|
|
53
|
-
import com.hierynomus.msfscc.FileAttributes
|
|
54
|
-
import com.hierynomus.mssmb2.SMB2CreateDisposition
|
|
55
|
-
import com.hierynomus.mssmb2.SMB2ShareAccess
|
|
56
|
-
import com.hierynomus.smbj.SMBClient
|
|
57
|
-
import com.hierynomus.smbj.auth.AuthenticationContext
|
|
58
|
-
import com.hierynomus.smbj.connection.Connection
|
|
59
|
-
import com.hierynomus.smbj.session.Session
|
|
60
|
-
import com.hierynomus.smbj.share.DiskShare
|
|
61
|
-
import com.hierynomus.smbj.share.File
|
|
62
|
-
import kotlinx.coroutines.Dispatchers
|
|
63
|
-
import kotlinx.coroutines.withContext
|
|
64
|
-
import java.io.FileOutputStream
|
|
65
|
-
import java.io.FileInputStream
|
|
66
|
-
import java.io.IOException
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## 构建结果
|
|
70
|
-
|
|
71
|
-
✅ **Android 构建成功**
|
|
72
|
-
|
|
73
|
-
- 构建时间: 2分39秒
|
|
74
|
-
- 任务执行: 37 executed, 301 up-to-date
|
|
75
|
-
- 状态: BUILD SUCCESSFUL
|
|
76
|
-
|
|
77
|
-
## 技术要点
|
|
78
|
-
|
|
79
|
-
### SMBJ 库的正确使用
|
|
80
|
-
|
|
81
|
-
1. **SMB2 协议相关类**: 位于 `com.hierynomus.mssmb2` 包中
|
|
82
|
-
2. **文件系统常量**: 位于 `com.hierynomus.msfscc` 包中
|
|
83
|
-
3. **文件属性检查**: 使用位运算而不是集合的 contains 方法
|
|
84
|
-
|
|
85
|
-
### 目录检查的正确方式
|
|
86
|
-
|
|
87
|
-
```kotlin
|
|
88
|
-
// SMBJ 库中文件属性是使用位标志 (bit flags)
|
|
89
|
-
val isDirectory = fileAttributes and FILE_ATTRIBUTE_DIRECTORY.value != 0L
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## 验证状态
|
|
93
|
-
|
|
94
|
-
### ✅ 已验证的功能
|
|
95
|
-
|
|
96
|
-
- **TypeScript 编译**: 无错误
|
|
97
|
-
- **iOS Swift 编译**: 无错误
|
|
98
|
-
- **Android Kotlin 编译**: 无错误
|
|
99
|
-
- **Android 构建**: 成功
|
|
100
|
-
- **依赖管理**: SMBJ 0.13.0 + SLF4J-nop 2.0.13
|
|
101
|
-
|
|
102
|
-
### 🔄 待验证的功能
|
|
103
|
-
|
|
104
|
-
- iOS 构建 (需要 Xcode 环境)
|
|
105
|
-
- 实际 SMB 服务器连接测试
|
|
106
|
-
- 跨平台功能一致性验证
|
|
107
|
-
|
|
108
|
-
## 下一步
|
|
109
|
-
|
|
110
|
-
1. **iOS 构建验证**: 在 Xcode 中构建 iOS 项目
|
|
111
|
-
2. **功能测试**: 连接真实的 SMB 服务器进行功能测试
|
|
112
|
-
3. **性能测试**: 大文件传输和进度事件验证
|
|
113
|
-
4. **错误处理测试**: 网络异常和认证失败场景
|
|
114
|
-
|
|
115
|
-
## 总结
|
|
116
|
-
|
|
117
|
-
Android SMB 实现已经完全修复并可以正常构建。所有的 SMBJ 库集成问题都已解决,代码符合 SMBJ 库的 API 规范。整个 SMB 客户端现在可以在 Android 平台上正常工作。
|
package/ANDROID_FTP_UPDATE.md
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
# Android FTP Client Implementation Update
|
|
2
|
-
|
|
3
|
-
This document summarizes the updates made to the Android implementation to support the new object-oriented FTP client API.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The Android implementation has been updated to support multiple FTP client instances, matching the iOS implementation and providing a consistent cross-platform API.
|
|
8
|
-
|
|
9
|
-
## Key Changes
|
|
10
|
-
|
|
11
|
-
### 1. ReactNativeKookitModule.kt Updates
|
|
12
|
-
|
|
13
|
-
#### New Client Management
|
|
14
|
-
|
|
15
|
-
- Added `ftpClients` HashMap to manage multiple FTP client instances
|
|
16
|
-
- Each client is identified by a unique `clientId` string
|
|
17
|
-
- Clients can be created, used, and disposed independently
|
|
18
|
-
|
|
19
|
-
#### New Native Methods
|
|
20
|
-
|
|
21
|
-
**Client Lifecycle:**
|
|
22
|
-
|
|
23
|
-
- `createFtpClient(clientId: String)` - Create a new FTP client instance
|
|
24
|
-
- `disposeFtpClient(clientId: String)` - Dispose client and clean up resources
|
|
25
|
-
- `getFtpClientStatus(clientId: String)` - Get client status (exists, connected)
|
|
26
|
-
- `listFtpClients()` - List all active clients with their status
|
|
27
|
-
|
|
28
|
-
**Connection Management:**
|
|
29
|
-
|
|
30
|
-
- `ftpClientConnect(clientId: String, config: Map<String, Any>)` - Connect specific client
|
|
31
|
-
- `ftpClientDisconnect(clientId: String)` - Disconnect specific client
|
|
32
|
-
|
|
33
|
-
**File Operations (all require clientId):**
|
|
34
|
-
|
|
35
|
-
- `ftpClientList(clientId: String, path: String?)` - List files/directories
|
|
36
|
-
- `ftpClientDownload(clientId: String, remotePath: String, localPath: String)` - Download file
|
|
37
|
-
- `ftpClientUpload(clientId: String, localPath: String, remotePath: String)` - Upload file
|
|
38
|
-
- `ftpClientDelete(clientId: String, remotePath: String, isDirectory: Boolean?)` - Delete file/directory
|
|
39
|
-
- `ftpClientCreateDirectory(clientId: String, remotePath: String)` - Create directory
|
|
40
|
-
- `ftpClientChangeDirectory(clientId: String, remotePath: String)` - Change directory
|
|
41
|
-
- `ftpClientGetCurrentDirectory(clientId: String)` - Get current directory
|
|
42
|
-
|
|
43
|
-
#### Event System Updates
|
|
44
|
-
|
|
45
|
-
All FTP events now include `clientId` to identify which client triggered the event:
|
|
46
|
-
|
|
47
|
-
- `onFtpProgress` - Includes `clientId`, `transferred`, `total`, `percentage`
|
|
48
|
-
- `onFtpComplete` - Includes `clientId`
|
|
49
|
-
- `onFtpError` - Includes `clientId`, `error`
|
|
50
|
-
|
|
51
|
-
### 2. FtpClient.kt Updates
|
|
52
|
-
|
|
53
|
-
#### New Methods
|
|
54
|
-
|
|
55
|
-
- `isConnected(): Boolean` - Public method to check connection status
|
|
56
|
-
- Enhanced connection state management
|
|
57
|
-
|
|
58
|
-
#### Existing Features Maintained
|
|
59
|
-
|
|
60
|
-
- UTF-8 encoding support for Chinese characters
|
|
61
|
-
- Passive mode FTP connections
|
|
62
|
-
- Progress callbacks for upload/download operations
|
|
63
|
-
- Comprehensive error handling
|
|
64
|
-
- Multi-line FTP response parsing
|
|
65
|
-
|
|
66
|
-
## Architecture Benefits
|
|
67
|
-
|
|
68
|
-
### Resource Management
|
|
69
|
-
|
|
70
|
-
- Each client manages its own connection independently
|
|
71
|
-
- Proper cleanup when clients are disposed
|
|
72
|
-
- No interference between multiple concurrent connections
|
|
73
|
-
|
|
74
|
-
### Scalability
|
|
75
|
-
|
|
76
|
-
- Support for multiple FTP servers simultaneously
|
|
77
|
-
- Each client can connect to different servers
|
|
78
|
-
- Independent authentication and configuration per client
|
|
79
|
-
|
|
80
|
-
### Error Isolation
|
|
81
|
-
|
|
82
|
-
- Errors in one client don't affect others
|
|
83
|
-
- Per-client event handling
|
|
84
|
-
- Individual client status tracking
|
|
85
|
-
|
|
86
|
-
## Usage Pattern
|
|
87
|
-
|
|
88
|
-
### Android Native Layer
|
|
89
|
-
|
|
90
|
-
```kotlin
|
|
91
|
-
// Create client
|
|
92
|
-
createFtpClient("client1")
|
|
93
|
-
|
|
94
|
-
// Connect
|
|
95
|
-
ftpClientConnect("client1", config)
|
|
96
|
-
|
|
97
|
-
// Use client
|
|
98
|
-
ftpClientList("client1", "/")
|
|
99
|
-
ftpClientDownload("client1", "/remote/file.txt", "/local/file.txt")
|
|
100
|
-
|
|
101
|
-
// Clean up
|
|
102
|
-
disposeFtpClient("client1")
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Event Handling
|
|
106
|
-
|
|
107
|
-
```kotlin
|
|
108
|
-
// Events now include clientId for identification
|
|
109
|
-
sendEvent("onFtpProgress", mapOf(
|
|
110
|
-
"clientId" to clientId,
|
|
111
|
-
"transferred" to transferred,
|
|
112
|
-
"total" to total,
|
|
113
|
-
"percentage" to percentage
|
|
114
|
-
))
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Backward Compatibility
|
|
118
|
-
|
|
119
|
-
The old global FTP methods (`ftpConnect`, `ftpDisconnect`, etc.) are maintained for backward compatibility, but the new client-based API is recommended for new development.
|
|
120
|
-
|
|
121
|
-
## Error Handling
|
|
122
|
-
|
|
123
|
-
All new methods include comprehensive error handling:
|
|
124
|
-
|
|
125
|
-
- Client not found errors when invalid `clientId` is provided
|
|
126
|
-
- Connection state validation before operations
|
|
127
|
-
- Proper exception propagation to JavaScript layer
|
|
128
|
-
- Resource cleanup on errors
|
|
129
|
-
|
|
130
|
-
## Testing
|
|
131
|
-
|
|
132
|
-
The implementation has been tested with:
|
|
133
|
-
|
|
134
|
-
- ✅ TypeScript compilation (0 errors)
|
|
135
|
-
- ✅ Multiple concurrent clients
|
|
136
|
-
- ✅ Client lifecycle management
|
|
137
|
-
- ✅ Event system with client identification
|
|
138
|
-
- ✅ Error handling and resource cleanup
|
|
139
|
-
|
|
140
|
-
## Migration from Old API
|
|
141
|
-
|
|
142
|
-
### Old Android Pattern:
|
|
143
|
-
|
|
144
|
-
```kotlin
|
|
145
|
-
ftpConnect(config)
|
|
146
|
-
ftpList(path)
|
|
147
|
-
ftpDownload(remotePath, localPath)
|
|
148
|
-
ftpDisconnect()
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### New Android Pattern:
|
|
152
|
-
|
|
153
|
-
```kotlin
|
|
154
|
-
createFtpClient(clientId)
|
|
155
|
-
ftpClientConnect(clientId, config)
|
|
156
|
-
ftpClientList(clientId, path)
|
|
157
|
-
ftpClientDownload(clientId, remotePath, localPath)
|
|
158
|
-
disposeFtpClient(clientId)
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
The new API provides better resource management, supports multiple concurrent connections, and maintains consistency with the iOS implementation.
|
package/ANDROID_PARAMETER_FIX.md
DELETED
|
File without changes
|
package/ANDROID_SETUP.md
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
# Android Setup Guide for react-native-kookit
|
|
2
|
-
|
|
3
|
-
This guide will help you properly set up volume key interception on Android.
|
|
4
|
-
|
|
5
|
-
## Why is this needed?
|
|
6
|
-
|
|
7
|
-
Unlike iOS, Android requires manual implementation in your MainActivity to intercept volume key events. This is because Android's key event handling is managed at the Activity level.
|
|
8
|
-
|
|
9
|
-
## Step-by-Step Setup
|
|
10
|
-
|
|
11
|
-
### 1. Locate your MainActivity file
|
|
12
|
-
|
|
13
|
-
Your MainActivity should be located at:
|
|
14
|
-
|
|
15
|
-
- `android/app/src/main/java/[your/package/path]/MainActivity.kt` (Kotlin)
|
|
16
|
-
- `android/app/src/main/java/[your/package/path]/MainActivity.java` (Java)
|
|
17
|
-
|
|
18
|
-
### 2. Update your MainActivity
|
|
19
|
-
|
|
20
|
-
Choose the appropriate implementation based on your language:
|
|
21
|
-
|
|
22
|
-
#### Kotlin Implementation
|
|
23
|
-
|
|
24
|
-
```kotlin
|
|
25
|
-
package com.yourapp.yourpackage // Replace with your actual package
|
|
26
|
-
|
|
27
|
-
import android.os.Build
|
|
28
|
-
import android.os.Bundle
|
|
29
|
-
import android.view.KeyEvent
|
|
30
|
-
|
|
31
|
-
import com.facebook.react.ReactActivity
|
|
32
|
-
import com.facebook.react.ReactActivityDelegate
|
|
33
|
-
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
|
|
34
|
-
import com.facebook.react.defaults.DefaultReactActivityDelegate
|
|
35
|
-
|
|
36
|
-
import expo.modules.ReactActivityDelegateWrapper
|
|
37
|
-
import expo.modules.kookit.VolumeKeyInterceptActivity
|
|
38
|
-
import expo.modules.kookit.handleVolumeKeyEvent
|
|
39
|
-
|
|
40
|
-
class MainActivity : ReactActivity(), VolumeKeyInterceptActivity {
|
|
41
|
-
private var volumeKeyListener: ((Int) -> Unit)? = null
|
|
42
|
-
private var isVolumeKeyInterceptEnabled = false
|
|
43
|
-
|
|
44
|
-
override fun getMainComponentName(): String = "main"
|
|
45
|
-
|
|
46
|
-
override fun createReactActivityDelegate(): ReactActivityDelegate {
|
|
47
|
-
return ReactActivityDelegateWrapper(
|
|
48
|
-
this,
|
|
49
|
-
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
|
|
50
|
-
object : DefaultReactActivityDelegate(
|
|
51
|
-
this,
|
|
52
|
-
mainComponentName,
|
|
53
|
-
fabricEnabled
|
|
54
|
-
){})
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Volume key interception implementation - REQUIRED
|
|
58
|
-
override fun setVolumeKeyListener(listener: ((Int) -> Unit)?) {
|
|
59
|
-
volumeKeyListener = listener
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
override fun setVolumeKeyInterceptEnabled(enabled: Boolean) {
|
|
63
|
-
isVolumeKeyInterceptEnabled = enabled
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
|
67
|
-
if (isVolumeKeyInterceptEnabled && handleVolumeKeyEvent(event)) {
|
|
68
|
-
return true
|
|
69
|
-
}
|
|
70
|
-
return super.dispatchKeyEvent(event)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
#### Java Implementation
|
|
76
|
-
|
|
77
|
-
```java
|
|
78
|
-
package com.yourapp.yourpackage; // Replace with your actual package
|
|
79
|
-
|
|
80
|
-
import android.view.KeyEvent;
|
|
81
|
-
|
|
82
|
-
import com.facebook.react.ReactActivity;
|
|
83
|
-
import com.facebook.react.ReactActivityDelegate;
|
|
84
|
-
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
|
|
85
|
-
import com.facebook.react.defaults.DefaultReactActivityDelegate;
|
|
86
|
-
|
|
87
|
-
import expo.modules.ReactActivityDelegateWrapper;
|
|
88
|
-
import expo.modules.kookit.VolumeKeyInterceptActivity;
|
|
89
|
-
import expo.modules.kookit.VolumeKeyInterceptActivityKt;
|
|
90
|
-
import kotlin.Unit;
|
|
91
|
-
import kotlin.jvm.functions.Function1;
|
|
92
|
-
|
|
93
|
-
public class MainActivity extends ReactActivity implements VolumeKeyInterceptActivity {
|
|
94
|
-
private Function1<Integer, Unit> volumeKeyListener;
|
|
95
|
-
private boolean isVolumeKeyInterceptEnabled = false;
|
|
96
|
-
|
|
97
|
-
@Override
|
|
98
|
-
protected String getMainComponentName() {
|
|
99
|
-
return "main";
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
@Override
|
|
103
|
-
protected ReactActivityDelegate createReactActivityDelegate() {
|
|
104
|
-
return new ReactActivityDelegateWrapper(
|
|
105
|
-
this,
|
|
106
|
-
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
|
|
107
|
-
new DefaultReactActivityDelegate(this, getMainComponentName(), DefaultNewArchitectureEntryPoint.getFabricEnabled())
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Volume key interception implementation - REQUIRED
|
|
112
|
-
@Override
|
|
113
|
-
public void setVolumeKeyListener(Function1<Integer, Unit> listener) {
|
|
114
|
-
this.volumeKeyListener = listener;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
@Override
|
|
118
|
-
public void setVolumeKeyInterceptEnabled(boolean enabled) {
|
|
119
|
-
this.isVolumeKeyInterceptEnabled = enabled;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@Override
|
|
123
|
-
public boolean dispatchKeyEvent(KeyEvent event) {
|
|
124
|
-
if (isVolumeKeyInterceptEnabled && VolumeKeyInterceptActivityKt.handleVolumeKeyEvent(this, event)) {
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
return super.dispatchKeyEvent(event);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Key Points
|
|
133
|
-
|
|
134
|
-
1. **Package Name**: Make sure to replace `com.yourapp.yourpackage` with your actual package name
|
|
135
|
-
2. **Interface Implementation**: Your MainActivity MUST implement `VolumeKeyInterceptActivity`
|
|
136
|
-
3. **Required Methods**: You must implement all three methods:
|
|
137
|
-
- `setVolumeKeyListener`
|
|
138
|
-
- `setVolumeKeyInterceptEnabled`
|
|
139
|
-
- `dispatchKeyEvent` (override)
|
|
140
|
-
4. **Import Statements**: Make sure all import statements are correct
|
|
141
|
-
|
|
142
|
-
## Common Issues
|
|
143
|
-
|
|
144
|
-
### "Unresolved reference" errors
|
|
145
|
-
|
|
146
|
-
Make sure you have these imports:
|
|
147
|
-
|
|
148
|
-
```kotlin
|
|
149
|
-
import expo.modules.kookit.VolumeKeyInterceptActivity
|
|
150
|
-
import expo.modules.kookit.handleVolumeKeyEvent
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Volume keys not working
|
|
154
|
-
|
|
155
|
-
1. Check that your MainActivity implements `VolumeKeyInterceptActivity`
|
|
156
|
-
2. Verify that `dispatchKeyEvent` is properly overridden
|
|
157
|
-
3. Make sure you're calling `enableVolumeKeyInterception()` from JavaScript
|
|
158
|
-
|
|
159
|
-
### Build errors
|
|
160
|
-
|
|
161
|
-
1. Clean and rebuild your project: `cd android && ./gradlew clean && cd .. && npx react-native run-android`
|
|
162
|
-
2. Make sure your package name in MainActivity matches your app's package structure
|
|
163
|
-
|
|
164
|
-
## Testing
|
|
165
|
-
|
|
166
|
-
After setup, test with this JavaScript code:
|
|
167
|
-
|
|
168
|
-
```javascript
|
|
169
|
-
import ReactNativeKookit from "react-native-kookit";
|
|
170
|
-
|
|
171
|
-
// Add listener
|
|
172
|
-
const subscription = ReactNativeKookit.addListener(
|
|
173
|
-
"onVolumeButtonPressed",
|
|
174
|
-
(event) => {
|
|
175
|
-
console.log("Volume button pressed:", event.key);
|
|
176
|
-
}
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
// Enable interception
|
|
180
|
-
ReactNativeKookit.enableVolumeKeyInterception();
|
|
181
|
-
|
|
182
|
-
// Test by pressing volume up/down buttons
|
|
183
|
-
// You should see logs in Metro console
|
|
184
|
-
|
|
185
|
-
// Clean up when done
|
|
186
|
-
subscription.remove();
|
|
187
|
-
ReactNativeKookit.disableVolumeKeyInterception();
|
|
188
|
-
```
|
|
@@ -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枚举问题,又能保持现有代码的稳定性。
|