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.
@@ -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`。
package/FTP_CLIENT_API.md DELETED
@@ -1,301 +0,0 @@
1
- # FTP Client API
2
-
3
- This document describes the new FTP Client API that provides an object-oriented approach to FTP operations.
4
-
5
- ## Overview
6
-
7
- The new FTP API allows you to create multiple FTP client instances, each maintaining its own connection and state. This is more flexible than the previous global FTP functions.
8
-
9
- ## Basic Usage
10
-
11
- ### Creating an FTP Client
12
-
13
- ```typescript
14
- import { FtpClient } from "react-native-kookit";
15
-
16
- // Method 1: Using static create method (recommended)
17
- const ftpClient = await FtpClient.create("my-client-id");
18
-
19
- // Method 2: Manual initialization
20
- const ftpClient = new FtpClient("my-client-id");
21
- await ftpClient.initialize();
22
- ```
23
-
24
- ### Setting up Event Handlers
25
-
26
- ```typescript
27
- ftpClient.setEventHandlers({
28
- onProgress: (progress) => {
29
- console.log(`Progress: ${progress.percentage}%`);
30
- console.log(`Transferred: ${progress.transferred}/${progress.total} bytes`);
31
- },
32
- onComplete: () => {
33
- console.log("Operation completed successfully!");
34
- },
35
- onError: (error) => {
36
- console.error("FTP Error:", error.message);
37
- },
38
- });
39
- ```
40
-
41
- ### Connecting to FTP Server
42
-
43
- ```typescript
44
- await ftpClient.connect({
45
- host: "192.168.1.100",
46
- port: 21, // optional, defaults to 21
47
- username: "your-username",
48
- password: "your-password",
49
- passive: true, // optional, defaults to true
50
- timeout: 30, // optional, defaults to 30 seconds
51
- });
52
- ```
53
-
54
- ## FTP Operations
55
-
56
- ### Directory Operations
57
-
58
- ```typescript
59
- // Get current directory
60
- const currentDir = await ftpClient.getCurrentDirectory();
61
- console.log("Current directory:", currentDir);
62
-
63
- // Change directory
64
- await ftpClient.changeDirectory("/path/to/directory");
65
-
66
- // Create directory
67
- await ftpClient.createDirectory("/path/to/new-directory");
68
-
69
- // List files and directories
70
- const files = await ftpClient.list(); // List current directory
71
- const filesInPath = await ftpClient.list("/specific/path"); // List specific path
72
-
73
- files.forEach((file) => {
74
- console.log(
75
- `${file.name} - ${file.isDirectory ? "DIR" : "FILE"} - ${file.size} bytes`
76
- );
77
- });
78
- ```
79
-
80
- ### File Operations
81
-
82
- ```typescript
83
- // Download file
84
- await ftpClient.download("/remote/path/file.txt", "/local/path/file.txt");
85
-
86
- // Upload file
87
- await ftpClient.upload("/local/path/file.txt", "/remote/path/file.txt");
88
-
89
- // Delete file
90
- await ftpClient.delete("/remote/path/file.txt");
91
-
92
- // Delete directory
93
- await ftpClient.delete("/remote/path/directory", true); // true for directory
94
- ```
95
-
96
- ### Client Management
97
-
98
- ```typescript
99
- // Check client status
100
- const status = ftpClient.getStatus();
101
- console.log("Client exists:", status.exists);
102
- console.log("Client connected:", status.connected);
103
-
104
- // Check if connected (convenience method)
105
- if (ftpClient.isConnected()) {
106
- console.log("Client is ready for operations");
107
- }
108
-
109
- // Get client ID
110
- const clientId = ftpClient.getClientId();
111
- console.log("Client ID:", clientId);
112
-
113
- // Disconnect from server
114
- await ftpClient.disconnect();
115
-
116
- // Dispose client and clean up resources
117
- await ftpClient.dispose();
118
- ```
119
-
120
- ## Advanced Usage
121
-
122
- ### Multiple FTP Clients
123
-
124
- ```typescript
125
- import { FtpClient } from "react-native-kookit";
126
-
127
- // Create multiple clients for different servers
128
- const client1 = await FtpClient.create("server1");
129
- const client2 = await FtpClient.create("server2");
130
-
131
- // Connect to different servers
132
- await client1.connect({
133
- host: "ftp1.example.com",
134
- username: "user1",
135
- password: "pass1",
136
- });
137
-
138
- await client2.connect({
139
- host: "ftp2.example.com",
140
- username: "user2",
141
- password: "pass2",
142
- });
143
-
144
- // Perform operations on different servers simultaneously
145
- const [files1, files2] = await Promise.all([client1.list(), client2.list()]);
146
-
147
- // Clean up
148
- await Promise.all([client1.dispose(), client2.dispose()]);
149
- ```
150
-
151
- ### Managing All Clients
152
-
153
- ```typescript
154
- // List all active FTP clients
155
- const clientsInfo = FtpClient.listClients();
156
- console.log("Active clients:", clientsInfo.count);
157
- console.log("Clients details:", clientsInfo.clients);
158
-
159
- // Example output:
160
- // {
161
- // clients: {
162
- // 'client-1': { connected: true },
163
- // 'client-2': { connected: false }
164
- // },
165
- // count: 2
166
- // }
167
- ```
168
-
169
- ### Error Handling
170
-
171
- ```typescript
172
- try {
173
- const ftpClient = await FtpClient.create();
174
-
175
- await ftpClient.connect({
176
- host: "ftp.example.com",
177
- username: "user",
178
- password: "pass",
179
- });
180
-
181
- await ftpClient.download("/remote/file.txt", "/local/file.txt");
182
- } catch (error) {
183
- console.error("FTP operation failed:", error.message);
184
- } finally {
185
- // Always dispose to clean up resources
186
- if (ftpClient) {
187
- await ftpClient.dispose();
188
- }
189
- }
190
- ```
191
-
192
- ## API Reference
193
-
194
- ### FtpClient Class
195
-
196
- #### Constructor
197
-
198
- - `new FtpClient(clientId?: string)` - Create a new FTP client instance
199
-
200
- #### Static Methods
201
-
202
- - `FtpClient.create(clientId?: string): Promise<FtpClient>` - Create and initialize a new FTP client
203
- - `FtpClient.listClients()` - Get information about all active FTP clients
204
-
205
- #### Instance Methods
206
-
207
- **Lifecycle:**
208
-
209
- - `initialize(): Promise<void>` - Initialize the client (called automatically by `create()`)
210
- - `dispose(): Promise<void>` - Dispose client and clean up resources
211
-
212
- **Connection:**
213
-
214
- - `connect(config: FtpConnectionConfig): Promise<void>` - Connect to FTP server
215
- - `disconnect(): Promise<void>` - Disconnect from FTP server
216
- - `isConnected(): boolean` - Check if client is connected
217
-
218
- **Directory Operations:**
219
-
220
- - `list(path?: string): Promise<FtpFileInfo[]>` - List files and directories
221
- - `getCurrentDirectory(): Promise<string>` - Get current working directory
222
- - `changeDirectory(path: string): Promise<void>` - Change working directory
223
- - `createDirectory(path: string): Promise<void>` - Create a directory
224
-
225
- **File Operations:**
226
-
227
- - `download(remotePath: string, localPath: string): Promise<void>` - Download a file
228
- - `upload(localPath: string, remotePath: string): Promise<void>` - Upload a file
229
- - `delete(remotePath: string, isDirectory?: boolean): Promise<void>` - Delete a file or directory
230
-
231
- **Utility:**
232
-
233
- - `getStatus()` - Get client status information
234
- - `getClientId(): string` - Get the client ID
235
- - `setEventHandlers(handlers: FtpClientEventHandlers): void` - Set event handlers
236
-
237
- ### Types
238
-
239
- ```typescript
240
- interface FtpConnectionConfig {
241
- host: string;
242
- port?: number;
243
- username: string;
244
- password: string;
245
- passive?: boolean;
246
- timeout?: number;
247
- }
248
-
249
- interface FtpFileInfo {
250
- name: string;
251
- isDirectory: boolean;
252
- size: number;
253
- lastModified: string;
254
- permissions?: string;
255
- }
256
-
257
- interface FtpClientEventHandlers {
258
- onProgress?: (progress: {
259
- transferred: number;
260
- total: number;
261
- percentage: number;
262
- }) => void;
263
- onComplete?: () => void;
264
- onError?: (error: Error) => void;
265
- }
266
- ```
267
-
268
- ## Migration from Old API
269
-
270
- If you're migrating from the old global FTP functions, here's how to update your code:
271
-
272
- ### Old API:
273
-
274
- ```typescript
275
- import ReactNativeKookitModule from "react-native-kookit";
276
-
277
- await ReactNativeKookitModule.ftpConnect(config);
278
- const files = await ReactNativeKookitModule.ftpList();
279
- await ReactNativeKookitModule.ftpDownload(remotePath, localPath);
280
- await ReactNativeKookitModule.ftpDisconnect();
281
- ```
282
-
283
- ### New API:
284
-
285
- ```typescript
286
- import { FtpClient } from "react-native-kookit";
287
-
288
- const ftpClient = await FtpClient.create();
289
- await ftpClient.connect(config);
290
- const files = await ftpClient.list();
291
- await ftpClient.download(remotePath, localPath);
292
- await ftpClient.dispose(); // This disconnects and cleans up
293
- ```
294
-
295
- ## Best Practices
296
-
297
- 1. **Always dispose clients**: Call `dispose()` when you're done to clean up resources
298
- 2. **Use try-finally blocks**: Ensure disposal happens even if operations fail
299
- 3. **Handle events**: Set up progress, completion, and error handlers for better UX
300
- 4. **Use meaningful client IDs**: This helps with debugging and client management
301
- 5. **Check connection status**: Use `isConnected()` before performing operations