react-native-kookit 0.1.5 → 0.1.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.
- package/app.json +5 -0
- package/ios/ReactNativeKookitModule.swift +5 -113
- package/package.json +8 -3
package/app.json
ADDED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import ExpoModulesCore
|
|
2
|
-
import MediaPlayer
|
|
3
|
-
import AVFoundation
|
|
4
2
|
|
|
5
3
|
public class ReactNativeKookitModule: Module {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
// Each module class must implement the definition function. The definition consists of components
|
|
5
|
+
// that describes the module's functionality and behavior.
|
|
6
|
+
// See https://docs.expo.dev/modules/module-api for more details about available components.
|
|
10
7
|
public func definition() -> ModuleDefinition {
|
|
11
8
|
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
|
|
12
9
|
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
|
|
@@ -19,17 +16,7 @@ public class ReactNativeKookitModule: Module {
|
|
|
19
16
|
])
|
|
20
17
|
|
|
21
18
|
// Defines event names that the module can send to JavaScript.
|
|
22
|
-
Events("onChange"
|
|
23
|
-
|
|
24
|
-
// Function to enable volume key interception
|
|
25
|
-
Function("enableVolumeKeyInterception") {
|
|
26
|
-
self.enableVolumeKeyInterception()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Function to disable volume key interception
|
|
30
|
-
Function("disableVolumeKeyInterception") {
|
|
31
|
-
self.disableVolumeKeyInterception()
|
|
32
|
-
}
|
|
19
|
+
Events("onChange")
|
|
33
20
|
|
|
34
21
|
// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
|
|
35
22
|
Function("hello") {
|
|
@@ -58,99 +45,4 @@ public class ReactNativeKookitModule: Module {
|
|
|
58
45
|
Events("onLoad")
|
|
59
46
|
}
|
|
60
47
|
}
|
|
61
|
-
|
|
62
|
-
private func enableVolumeKeyInterception() {
|
|
63
|
-
guard !isVolumeListenerEnabled else { return }
|
|
64
|
-
|
|
65
|
-
isVolumeListenerEnabled = true
|
|
66
|
-
|
|
67
|
-
// Store initial volume to restore it later
|
|
68
|
-
initialVolume = AVAudioSession.sharedInstance().outputVolume
|
|
69
|
-
|
|
70
|
-
// Create a hidden MPVolumeView to intercept volume button presses
|
|
71
|
-
volumeView = MPVolumeView(frame: CGRect(x: -2000, y: -2000, width: 1, height: 1))
|
|
72
|
-
volumeView?.showsVolumeSlider = true // Need to show slider to intercept
|
|
73
|
-
volumeView?.showsRouteButton = false
|
|
74
|
-
volumeView?.isUserInteractionEnabled = false
|
|
75
|
-
volumeView?.alpha = 0.01 // Make it almost invisible
|
|
76
|
-
volumeView?.clipsToBounds = true
|
|
77
|
-
|
|
78
|
-
// Add to main window and make sure it's hidden
|
|
79
|
-
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
|
80
|
-
let window = windowScene.windows.first {
|
|
81
|
-
window.addSubview(volumeView!)
|
|
82
|
-
volumeView?.isHidden = false
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Listen for volume changes using KVO
|
|
86
|
-
AVAudioSession.sharedInstance().addObserver(
|
|
87
|
-
self,
|
|
88
|
-
forKeyPath: "outputVolume",
|
|
89
|
-
options: [.new, .old],
|
|
90
|
-
context: nil
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
// Also use notification as backup
|
|
94
|
-
NotificationCenter.default.addObserver(
|
|
95
|
-
self,
|
|
96
|
-
selector: #selector(systemVolumeChanged),
|
|
97
|
-
name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"),
|
|
98
|
-
object: nil
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private func disableVolumeKeyInterception() {
|
|
103
|
-
guard isVolumeListenerEnabled else { return }
|
|
104
|
-
|
|
105
|
-
isVolumeListenerEnabled = false
|
|
106
|
-
|
|
107
|
-
// Remove KVO observer
|
|
108
|
-
AVAudioSession.sharedInstance().removeObserver(self, forKeyPath: "outputVolume")
|
|
109
|
-
|
|
110
|
-
// Remove volume view
|
|
111
|
-
volumeView?.removeFromSuperview()
|
|
112
|
-
volumeView = nil
|
|
113
|
-
|
|
114
|
-
// Remove notification observers
|
|
115
|
-
NotificationCenter.default.removeObserver(self)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
|
119
|
-
guard isVolumeListenerEnabled,
|
|
120
|
-
keyPath == "outputVolume",
|
|
121
|
-
let change = change else { return }
|
|
122
|
-
|
|
123
|
-
let newVolume = change[.newKey] as? Float ?? initialVolume
|
|
124
|
-
let oldVolume = change[.oldKey] as? Float ?? initialVolume
|
|
125
|
-
|
|
126
|
-
// Determine direction
|
|
127
|
-
let keyType: String
|
|
128
|
-
if newVolume > oldVolume {
|
|
129
|
-
keyType = "up"
|
|
130
|
-
} else if newVolume < oldVolume {
|
|
131
|
-
keyType = "down"
|
|
132
|
-
} else {
|
|
133
|
-
return // No change
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Reset volume to initial value to prevent actual volume change
|
|
137
|
-
DispatchQueue.main.async {
|
|
138
|
-
// Find the volume slider and set it back
|
|
139
|
-
if let volumeSlider = self.volumeView?.subviews.compactMap({ $0 as? UISlider }).first {
|
|
140
|
-
volumeSlider.setValue(self.initialVolume, animated: false)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Send event to JavaScript
|
|
145
|
-
sendEvent("onVolumeButtonPressed", [
|
|
146
|
-
"key": keyType
|
|
147
|
-
])
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
@objc private func systemVolumeChanged(_ notification: Notification) {
|
|
151
|
-
// This is a backup method in case KVO doesn't work
|
|
152
|
-
guard isVolumeListenerEnabled else { return }
|
|
153
|
-
|
|
154
|
-
// The main logic is handled in observeValue
|
|
155
|
-
}
|
|
156
|
-
}
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-kookit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "React Native module for intercepting volume button presses on iOS and Android",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
"prepublishOnly": "expo-module prepublishOnly && npm run build-plugin",
|
|
15
15
|
"expo-module": "expo-module",
|
|
16
16
|
"open:ios": "xed example/ios",
|
|
17
|
-
"open:android": "open -a \"Android Studio\" example/android"
|
|
17
|
+
"open:android": "open -a \"Android Studio\" example/android",
|
|
18
|
+
"android": "expo run:android",
|
|
19
|
+
"ios": "expo run:ios"
|
|
18
20
|
},
|
|
19
21
|
"keywords": [
|
|
20
22
|
"react-native",
|
|
@@ -33,7 +35,10 @@
|
|
|
33
35
|
"license": "MIT",
|
|
34
36
|
"homepage": "https://github.com/troyeguo/react-native-kookit#readme",
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@expo/config-plugins": "^8.0.0"
|
|
38
|
+
"@expo/config-plugins": "^8.0.0",
|
|
39
|
+
"expo": "~53.0.20",
|
|
40
|
+
"react": "19.0.0",
|
|
41
|
+
"react-native": "0.79.5"
|
|
37
42
|
},
|
|
38
43
|
"devDependencies": {
|
|
39
44
|
"@types/react": "~19.0.0",
|