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 +1 @@
1
- {"version":3,"file":"ReactNativeKookitModule.d.ts","sourceRoot":"","sources":["../src/ReactNativeKookitModule.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ReactNativeKookitModule.d.ts","sourceRoot":"","sources":["../src/ReactNativeKookitModule.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ReactNativeKookitModule.js","sourceRoot":"","sources":["../src/ReactNativeKookitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAmMzD,yDAAyD;AACzD,eAAe,mBAAmB,CAChC,mBAAmB,CACpB,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo\";\n\nimport {\n ReactNativeKookitModuleEvents,\n FtpConnectionConfig,\n FtpFileInfo,\n SmbConnectionConfig,\n SmbFileInfo,\n} from \"./ReactNativeKookit.types\";\n\ndeclare class ReactNativeKookitModule extends NativeModule<ReactNativeKookitModuleEvents> {\n PI: number;\n\n /**\n * Returns a hello world string\n */\n hello(): string;\n\n /**\n * Test async function that sends a change event\n */\n setValueAsync(value: string): Promise<void>;\n\n /**\n * Enables volume key interception.\n * On Android, your MainActivity must implement VolumeKeyInterceptActivity interface.\n * On iOS, this works automatically.\n *\n * @throws Error if MainActivity doesn't implement VolumeKeyInterceptActivity on Android\n */\n enableVolumeKeyInterception(): void;\n\n /**\n * Disables volume key interception\n */\n disableVolumeKeyInterception(): void;\n\n // New FTP Client API Methods\n\n /**\n * Create a new FTP client instance\n * @param clientId Unique identifier for the FTP client\n * @returns Promise that resolves with client creation result\n */\n createFtpClient(clientId: string): Promise<{ clientId: string }>;\n\n /**\n * Connect FTP client to server\n * @param clientId FTP client identifier\n * @param config FTP connection configuration\n * @returns Promise that resolves when connected\n */\n ftpClientConnect(\n clientId: string,\n config: FtpConnectionConfig\n ): Promise<void>;\n\n /**\n * Disconnect FTP client from server\n * @param clientId FTP client identifier\n * @returns Promise that resolves when disconnected\n */\n ftpClientDisconnect(clientId: string): Promise<void>;\n\n /**\n * Dispose FTP client and clean up resources\n * @param clientId FTP client identifier\n * @returns Promise that resolves when disposed\n */\n disposeFtpClient(clientId: string): Promise<void>;\n\n /**\n * List files and directories\n * @param clientId FTP client identifier\n * @param path Optional path to list (defaults to current directory)\n * @returns Promise that resolves with array of file information\n */\n ftpClientList(clientId: string, path?: string): Promise<FtpFileInfo[]>;\n\n /**\n * Download a file from FTP server\n * @param clientId FTP client identifier\n * @param remotePath Remote file path on FTP server\n * @param localPath Local file path to save the downloaded file\n * @returns Promise that resolves when download is complete\n */\n ftpClientDownload(\n clientId: string,\n remotePath: string,\n localPath: string\n ): Promise<void>;\n\n /**\n * Upload a file to FTP server\n * @param clientId FTP client identifier\n * @param localPath Local file path to upload\n * @param remotePath Remote file path on FTP server\n * @returns Promise that resolves when upload is complete\n */\n ftpClientUpload(\n clientId: string,\n localPath: string,\n remotePath: string\n ): Promise<void>;\n\n /**\n * Delete a file or directory on FTP server\n * @param clientId FTP client identifier\n * @param remotePath Remote file or directory path to delete\n * @param isDirectory Whether the path is a directory (default: false)\n * @returns Promise that resolves when deletion is complete\n */\n ftpClientDelete(\n clientId: string,\n remotePath: string,\n isDirectory?: boolean\n ): Promise<void>;\n\n /**\n * Create a directory on FTP server\n * @param clientId FTP client identifier\n * @param remotePath Remote directory path to create\n * @returns Promise that resolves when directory is created\n */\n ftpClientCreateDirectory(clientId: string, remotePath: string): Promise<void>;\n\n /**\n * Change current working directory on FTP server\n * @param clientId FTP client identifier\n * @param remotePath Remote directory path to change to\n * @returns Promise that resolves when directory is changed\n */\n ftpClientChangeDirectory(clientId: string, remotePath: string): Promise<void>;\n\n /**\n * Get current working directory on FTP server\n * @param clientId FTP client identifier\n * @returns Promise that resolves with current directory path\n */\n ftpClientGetCurrentDirectory(clientId: string): Promise<string>;\n\n /**\n * Get FTP client status\n * @param clientId FTP client identifier\n * @returns Client status information\n */\n getFtpClientStatus(\n clientId: string\n ): Promise<{ exists: boolean; connected: boolean }>;\n\n /**\n * List all FTP clients\n * @returns Object containing all clients and their status\n */\n listFtpClients(): Promise<{\n clients: Record<string, { connected: boolean }>;\n count: number;\n }>;\n\n // SMB Client API\n\n createSmbClient(clientId: string): Promise<{ clientId: string }>;\n smbClientConnect(\n clientId: string,\n config: SmbConnectionConfig\n ): Promise<void>;\n smbClientConnectShare(clientId: string, shareName: string): Promise<void>;\n smbClientDisconnect(clientId: string): Promise<void>;\n disposeSmbClient(clientId: string): Promise<void>;\n smbClientList(clientId: string, path?: string): Promise<SmbFileInfo[]>;\n smbClientDownload(\n clientId: string,\n remotePath: string,\n localPath: string\n ): Promise<void>;\n smbClientUpload(\n clientId: string,\n localPath: string,\n remotePath: string\n ): Promise<void>;\n smbClientDelete(\n clientId: string,\n remotePath: string,\n isDirectory?: boolean\n ): Promise<void>;\n smbClientCreateDirectory(clientId: string, remotePath: string): Promise<void>;\n getSmbClientStatus(\n clientId: string\n ): Promise<{ exists: boolean; connected: boolean }>;\n listSmbClients(): Promise<{\n clients: Record<string, { connected: boolean }>;\n count: number;\n }>;\n}\n\n// This call loads the native module object from the JSI.\nexport default requireNativeModule<ReactNativeKookitModule>(\n \"ReactNativeKookit\"\n);\n"]}
1
+ {"version":3,"file":"ReactNativeKookitModule.js","sourceRoot":"","sources":["../src/ReactNativeKookitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AA+OzD,yDAAyD;AACzD,eAAe,mBAAmB,CAChC,mBAAmB,CACpB,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo\";\n\nimport {\n ReactNativeKookitModuleEvents,\n FtpConnectionConfig,\n FtpFileInfo,\n SmbConnectionConfig,\n SmbFileInfo,\n TtsSynthesizeOptions,\n TtsSynthesizeResult,\n} from \"./ReactNativeKookit.types\";\n\ndeclare class ReactNativeKookitModule extends NativeModule<ReactNativeKookitModuleEvents> {\n PI: number;\n\n /**\n * Returns a hello world string\n */\n hello(): string;\n\n /**\n * Test async function that sends a change event\n */\n setValueAsync(value: string): Promise<void>;\n\n /**\n * Enables volume key interception.\n * On Android, your MainActivity must implement VolumeKeyInterceptActivity interface.\n * On iOS, this works automatically.\n *\n * @throws Error if MainActivity doesn't implement VolumeKeyInterceptActivity on Android\n */\n enableVolumeKeyInterception(): void;\n\n /**\n * Disables volume key interception\n */\n disableVolumeKeyInterception(): void;\n\n // New FTP Client API Methods\n\n /**\n * Create a new FTP client instance\n * @param clientId Unique identifier for the FTP client\n * @returns Promise that resolves with client creation result\n */\n createFtpClient(clientId: string): Promise<{ clientId: string }>;\n\n /**\n * Connect FTP client to server\n * @param clientId FTP client identifier\n * @param config FTP connection configuration\n * @returns Promise that resolves when connected\n */\n ftpClientConnect(\n clientId: string,\n config: FtpConnectionConfig\n ): Promise<void>;\n\n /**\n * Disconnect FTP client from server\n * @param clientId FTP client identifier\n * @returns Promise that resolves when disconnected\n */\n ftpClientDisconnect(clientId: string): Promise<void>;\n\n /**\n * Dispose FTP client and clean up resources\n * @param clientId FTP client identifier\n * @returns Promise that resolves when disposed\n */\n disposeFtpClient(clientId: string): Promise<void>;\n\n /**\n * List files and directories\n * @param clientId FTP client identifier\n * @param path Optional path to list (defaults to current directory)\n * @returns Promise that resolves with array of file information\n */\n ftpClientList(clientId: string, path?: string): Promise<FtpFileInfo[]>;\n\n /**\n * Download a file from FTP server\n * @param clientId FTP client identifier\n * @param remotePath Remote file path on FTP server\n * @param localPath Local file path to save the downloaded file\n * @returns Promise that resolves when download is complete\n */\n ftpClientDownload(\n clientId: string,\n remotePath: string,\n localPath: string\n ): Promise<void>;\n\n /**\n * Upload a file to FTP server\n * @param clientId FTP client identifier\n * @param localPath Local file path to upload\n * @param remotePath Remote file path on FTP server\n * @returns Promise that resolves when upload is complete\n */\n ftpClientUpload(\n clientId: string,\n localPath: string,\n remotePath: string\n ): Promise<void>;\n\n /**\n * Delete a file or directory on FTP server\n * @param clientId FTP client identifier\n * @param remotePath Remote file or directory path to delete\n * @param isDirectory Whether the path is a directory (default: false)\n * @returns Promise that resolves when deletion is complete\n */\n ftpClientDelete(\n clientId: string,\n remotePath: string,\n isDirectory?: boolean\n ): Promise<void>;\n\n /**\n * Create a directory on FTP server\n * @param clientId FTP client identifier\n * @param remotePath Remote directory path to create\n * @returns Promise that resolves when directory is created\n */\n ftpClientCreateDirectory(clientId: string, remotePath: string): Promise<void>;\n\n /**\n * Change current working directory on FTP server\n * @param clientId FTP client identifier\n * @param remotePath Remote directory path to change to\n * @returns Promise that resolves when directory is changed\n */\n ftpClientChangeDirectory(clientId: string, remotePath: string): Promise<void>;\n\n /**\n * Get current working directory on FTP server\n * @param clientId FTP client identifier\n * @returns Promise that resolves with current directory path\n */\n ftpClientGetCurrentDirectory(clientId: string): Promise<string>;\n\n /**\n * Get FTP client status\n * @param clientId FTP client identifier\n * @returns Client status information\n */\n getFtpClientStatus(\n clientId: string\n ): Promise<{ exists: boolean; connected: boolean }>;\n\n /**\n * List all FTP clients\n * @returns Object containing all clients and their status\n */\n listFtpClients(): Promise<{\n clients: Record<string, { connected: boolean }>;\n count: number;\n }>;\n\n // SMB Client API\n\n createSmbClient(clientId: string): Promise<{ clientId: string }>;\n smbClientConnect(\n clientId: string,\n config: SmbConnectionConfig\n ): Promise<void>;\n smbClientConnectShare(clientId: string, shareName: string): Promise<void>;\n smbClientDisconnect(clientId: string): Promise<void>;\n disposeSmbClient(clientId: string): Promise<void>;\n smbClientList(clientId: string, path?: string): Promise<SmbFileInfo[]>;\n smbClientDownload(\n clientId: string,\n remotePath: string,\n localPath: string\n ): Promise<void>;\n smbClientUpload(\n clientId: string,\n localPath: string,\n remotePath: string\n ): Promise<void>;\n smbClientDelete(\n clientId: string,\n remotePath: string,\n isDirectory?: boolean\n ): Promise<void>;\n smbClientCreateDirectory(clientId: string, remotePath: string): Promise<void>;\n getSmbClientStatus(\n clientId: string\n ): Promise<{ exists: boolean; connected: boolean }>;\n listSmbClients(): Promise<{\n clients: Record<string, { connected: boolean }>;\n count: number;\n }>;\n\n /**\n * Copy a file from content:// URI to local cache directory.\n * This method uses Android's ContentResolver to read the file stream,\n * bypassing permission restrictions when receiving content URIs from other apps.\n *\n * @param contentUri The content:// URI received from another app (e.g., via Intent)\n * @param fileName Optional filename for the destination file. If not provided, tries to extract from URI\n * @returns Promise that resolves with the local file path (file://)\n * @platform android\n */\n copyContentUriToCache(\n contentUri: string,\n fileName?: string\n ): Promise<{\n localPath: string;\n fileName: string;\n mimeType?: string;\n size?: number;\n }>;\n\n /**\n * Get metadata about a content:// URI without copying the file.\n *\n * @param contentUri The content:// URI to query\n * @returns Promise that resolves with file metadata\n * @platform android\n */\n getContentUriMetadata(contentUri: string): Promise<{\n displayName?: string;\n mimeType?: string;\n size?: number;\n }>;\n\n /**\n * Synthesize speech from text and save to audio file.\n * The audio file will be saved in the cache directory under 'tts' folder.\n *\n * @param options TTS synthesis options including text, voiceId, language, pitch, and rate\n * @returns Promise that resolves with file path and duration of the generated audio\n */\n synthesizeSpeech(options: TtsSynthesizeOptions): Promise<TtsSynthesizeResult>;\n}\n\n// This call loads the native module object from the JSI.\nexport default requireNativeModule<ReactNativeKookitModule>(\n \"ReactNativeKookit\"\n);\n"]}
@@ -1022,6 +1022,8 @@ public class ReactNativeKookitModule: Module {
1022
1022
  private var previousVolume: Float = 0.0
1023
1023
  private var ftpClients: [String: FtpClient] = [:] // Store multiple FTP clients by ID
1024
1024
  private var smbClients: [String: SmbClient] = [:] // Store multiple SMB clients by ID
1025
+ private var speechSynthesizer: AVSpeechSynthesizer?
1026
+ private var currentSynthesisTask: Task<String, Error>?
1025
1027
 
1026
1028
  // Each module class must implement the definition function. The definition consists of components
1027
1029
  // that describes the module's functionality and behavior.
@@ -1547,6 +1549,47 @@ public class ReactNativeKookitModule: Module {
1547
1549
  }
1548
1550
  }
1549
1551
 
1552
+ // TTS (Text-to-Speech) Function
1553
+ AsyncFunction("synthesizeSpeech") { (options: [String: Any], promise: Promise) in
1554
+ Task {
1555
+ do {
1556
+ let text = options["text"] as? String ?? ""
1557
+ if text.isEmpty {
1558
+ promise.reject("TTS_ERROR", "Text is required")
1559
+ return
1560
+ }
1561
+
1562
+ let voiceId = options["voiceId"] as? String
1563
+ let language = options["language"] as? String ?? "en-US"
1564
+ let pitch = options["pitch"] as? Double ?? 1.0
1565
+ let rate = options["rate"] as? Double ?? 1.0
1566
+
1567
+ // Initialize synthesizer if needed
1568
+ if self.speechSynthesizer == nil {
1569
+ self.speechSynthesizer = AVSpeechSynthesizer()
1570
+ }
1571
+
1572
+ let filePath = try await self.synthesizeSpeechToFile(
1573
+ text: text,
1574
+ voiceId: voiceId,
1575
+ language: language,
1576
+ pitch: Float(pitch),
1577
+ rate: Float(rate)
1578
+ )
1579
+
1580
+ // Estimate duration
1581
+ let duration = self.estimateDuration(text: text, rate: Float(rate))
1582
+
1583
+ promise.resolve([
1584
+ "filePath": filePath,
1585
+ "duration": duration
1586
+ ])
1587
+ } catch {
1588
+ promise.reject("TTS_SYNTHESIS_ERROR", error.localizedDescription)
1589
+ }
1590
+ }
1591
+ }
1592
+
1550
1593
  // Enables the module to be used as a native view. Definition components that are accepted as part of
1551
1594
  // the view definition: Prop, Events.
1552
1595
  View(ReactNativeKookitView.self) {
@@ -1640,6 +1683,106 @@ public class ReactNativeKookitModule: Module {
1640
1683
  }
1641
1684
  }
1642
1685
  }
1686
+
1687
+ // MARK: - TTS Helper Methods
1688
+
1689
+ private func synthesizeSpeechToFile(text: String, voiceId: String?, language: String, pitch: Float, rate: Float) async throws -> String {
1690
+ return try await withCheckedThrowingContinuation { continuation in
1691
+ guard let synthesizer = self.speechSynthesizer else {
1692
+ continuation.resume(throwing: NSError(domain: "TTS", code: -1, userInfo: [NSLocalizedDescriptionKey: "Speech synthesizer not initialized"]))
1693
+ return
1694
+ }
1695
+
1696
+ let utterance = AVSpeechUtterance(string: text)
1697
+
1698
+ // Set voice
1699
+ if let voiceId = voiceId {
1700
+ utterance.voice = AVSpeechSynthesisVoice(identifier: voiceId)
1701
+ } else {
1702
+ // Try to find voice by language
1703
+ let voices = AVSpeechSynthesisVoice.speechVoices()
1704
+ if let voice = voices.first(where: { $0.language.hasPrefix(language) }) {
1705
+ utterance.voice = voice
1706
+ } else {
1707
+ utterance.voice = AVSpeechSynthesisVoice(language: language)
1708
+ }
1709
+ }
1710
+
1711
+ // Set pitch and rate
1712
+ utterance.pitchMultiplier = pitch
1713
+ utterance.rate = rate * AVSpeechUtteranceDefaultSpeechRate
1714
+
1715
+ // Create TTS cache directory
1716
+ let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
1717
+ let ttsDir = cacheDir.appendingPathComponent("tts")
1718
+
1719
+ do {
1720
+ try FileManager.default.createDirectory(at: ttsDir, withIntermediateDirectories: true, attributes: nil)
1721
+ } catch {
1722
+ continuation.resume(throwing: error)
1723
+ return
1724
+ }
1725
+
1726
+ // Generate unique filename
1727
+ let fileName = "tts_\(UUID().uuidString).caf"
1728
+ let outputURL = ttsDir.appendingPathComponent(fileName)
1729
+
1730
+ // Write utterance to file using AVSpeechSynthesizer.write
1731
+ Task {
1732
+ do {
1733
+ var audioBuffers: [AVAudioPCMBuffer] = []
1734
+
1735
+ synthesizer.write(utterance) { buffer in
1736
+ if let buffer = buffer as? AVAudioPCMBuffer {
1737
+ audioBuffers.append(buffer)
1738
+ } else if buffer == nil {
1739
+ // Writing is complete when buffer is nil
1740
+ Task {
1741
+ do {
1742
+ // Write all buffers to file
1743
+ try self.writeBuffersToFile(buffers: audioBuffers, url: outputURL)
1744
+ continuation.resume(returning: outputURL.path)
1745
+ } catch {
1746
+ continuation.resume(throwing: error)
1747
+ }
1748
+ }
1749
+ }
1750
+ }
1751
+ }
1752
+ }
1753
+ }
1754
+ }
1755
+
1756
+ private func writeBuffersToFile(buffers: [AVAudioPCMBuffer], url: URL) throws {
1757
+ guard let firstBuffer = buffers.first else {
1758
+ throw NSError(domain: "TTS", code: -1, userInfo: [NSLocalizedDescriptionKey: "No audio data generated"])
1759
+ }
1760
+
1761
+ // Create audio file with settings from the buffer
1762
+ let settings: [String: Any] = [
1763
+ AVFormatIDKey: kAudioFormatLinearPCM,
1764
+ AVSampleRateKey: firstBuffer.format.sampleRate,
1765
+ AVNumberOfChannelsKey: firstBuffer.format.channelCount,
1766
+ AVLinearPCMBitDepthKey: 16,
1767
+ AVLinearPCMIsFloatKey: false,
1768
+ AVLinearPCMIsBigEndianKey: false
1769
+ ]
1770
+
1771
+ let audioFile = try AVAudioFile(forWriting: url, settings: settings)
1772
+
1773
+ // Write all buffers to file
1774
+ for buffer in buffers {
1775
+ try audioFile.write(from: buffer)
1776
+ }
1777
+ }
1778
+
1779
+ private func estimateDuration(text: String, rate: Float) -> Double {
1780
+ // Average speaking rate is about 150 words per minute
1781
+ let words = text.split(separator: " ").count
1782
+ let baseMinutes = Double(words) / 150.0
1783
+ let durationSeconds = (baseMinutes * 60.0) / Double(rate)
1784
+ return durationSeconds
1785
+ }
1643
1786
  }
1644
1787
 
1645
1788
  // Helper class to handle FTP progress callbacks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-kookit",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "React Native module for intercepting volume button presses on iOS and Android, with FTP client functionality",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -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 平台上正常工作。
@@ -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_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
- ```