react-native-frame-capture 1.0.1 → 1.1.0

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.
Files changed (50) hide show
  1. package/FrameCapture.podspec +21 -21
  2. package/LICENSE +20 -20
  3. package/README.md +159 -158
  4. package/android/build.gradle +77 -77
  5. package/android/gradle.properties +5 -5
  6. package/android/src/main/AndroidManifest.xml +20 -20
  7. package/android/src/main/java/com/framecapture/CaptureManager.kt +1013 -831
  8. package/android/src/main/java/com/framecapture/Constants.kt +205 -196
  9. package/android/src/main/java/com/framecapture/ErrorHandler.kt +165 -165
  10. package/android/src/main/java/com/framecapture/FrameCaptureModule.kt +653 -653
  11. package/android/src/main/java/com/framecapture/OverlayRenderer.kt +423 -423
  12. package/android/src/main/java/com/framecapture/PermissionHandler.kt +150 -150
  13. package/android/src/main/java/com/framecapture/ScreenCaptureService.kt +366 -366
  14. package/android/src/main/java/com/framecapture/StorageManager.kt +221 -221
  15. package/android/src/main/java/com/framecapture/capture/BitmapProcessor.kt +157 -157
  16. package/android/src/main/java/com/framecapture/capture/CaptureEventEmitter.kt +150 -120
  17. package/android/src/main/java/com/framecapture/capture/ChangeDetector.kt +191 -0
  18. package/android/src/main/java/com/framecapture/models/CaptureModels.kt +343 -302
  19. package/android/src/main/java/com/framecapture/models/EnumsAndExtensions.kt +67 -60
  20. package/android/src/main/java/com/framecapture/models/OverlayModels.kt +154 -154
  21. package/android/src/main/java/com/framecapture/service/CaptureNotificationManager.kt +286 -286
  22. package/android/src/main/java/com/framecapture/storage/StorageStrategies.kt +317 -317
  23. package/android/src/main/java/com/framecapture/utils/ValidationUtils.kt +379 -379
  24. package/ios/FrameCapture.h +5 -5
  25. package/ios/FrameCapture.mm +21 -21
  26. package/lib/module/NativeFrameCapture.js.map +1 -1
  27. package/lib/module/constants.js +45 -0
  28. package/lib/module/constants.js.map +1 -1
  29. package/lib/module/normalize.js +10 -1
  30. package/lib/module/normalize.js.map +1 -1
  31. package/lib/module/types.js +9 -0
  32. package/lib/module/types.js.map +1 -1
  33. package/lib/module/validation.js +86 -9
  34. package/lib/module/validation.js.map +1 -1
  35. package/lib/typescript/src/NativeFrameCapture.d.ts +7 -0
  36. package/lib/typescript/src/NativeFrameCapture.d.ts.map +1 -1
  37. package/lib/typescript/src/constants.d.ts +33 -0
  38. package/lib/typescript/src/constants.d.ts.map +1 -1
  39. package/lib/typescript/src/normalize.d.ts +8 -2
  40. package/lib/typescript/src/normalize.d.ts.map +1 -1
  41. package/lib/typescript/src/types.d.ts +29 -5
  42. package/lib/typescript/src/types.d.ts.map +1 -1
  43. package/lib/typescript/src/validation.d.ts.map +1 -1
  44. package/package.json +199 -196
  45. package/src/NativeFrameCapture.ts +8 -0
  46. package/src/constants.ts +45 -0
  47. package/src/normalize.ts +23 -3
  48. package/src/types.ts +30 -2
  49. package/src/validation.ts +132 -13
  50. package/plugin/build/index.js +0 -48
package/package.json CHANGED
@@ -1,196 +1,199 @@
1
- {
2
- "name": "react-native-frame-capture",
3
- "version": "1.0.1",
4
- "description": "Reliable screen capture for React Native Android. Capture frames at intervals with customizable overlays and storage options.",
5
- "main": "./lib/module/index.js",
6
- "types": "./lib/typescript/src/index.d.ts",
7
- "exports": {
8
- ".": {
9
- "source": "./src/index.tsx",
10
- "types": "./lib/typescript/src/index.d.ts",
11
- "default": "./lib/module/index.js"
12
- },
13
- "./app.plugin.js": "./app.plugin.js",
14
- "./package.json": "./package.json"
15
- },
16
- "files": [
17
- "src",
18
- "lib",
19
- "android",
20
- "ios",
21
- "cpp",
22
- "plugin/build",
23
- "*.podspec",
24
- "react-native.config.js",
25
- "app.plugin.js",
26
- "!ios/build",
27
- "!android/build",
28
- "!android/gradle",
29
- "!android/gradlew",
30
- "!android/gradlew.bat",
31
- "!android/local.properties",
32
- "!**/__tests__",
33
- "!**/__fixtures__",
34
- "!**/__mocks__",
35
- "!**/.*"
36
- ],
37
- "scripts": {
38
- "example": "yarn workspace react-native-frame-capture-example",
39
- "test": "jest --passWithNoTests",
40
- "typecheck": "tsc",
41
- "lint": "eslint \"**/*.{js,ts,tsx}\"",
42
- "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
43
- "prepare": "bob build",
44
- "release": "release-it --only-version",
45
- "run-dev": "cd example/android && gradlew clean && cd ../../ && yarn prepare && yarn example android"
46
- },
47
- "keywords": [
48
- "react-native",
49
- "android",
50
- "screen-capture",
51
- "frame-capture",
52
- "screenshot",
53
- "screen-recording",
54
- "interval-capture",
55
- "media-projection",
56
- "turbo-module",
57
- "expo",
58
- "capture",
59
- "frame",
60
- "screen",
61
- "recording",
62
- "fps",
63
- "foreground-service",
64
- "overlay",
65
- "watermark",
66
- "image-overlay",
67
- "text-overlay",
68
- "kotlin",
69
- "typescript",
70
- "background-capture",
71
- "periodic-capture"
72
- ],
73
- "repository": {
74
- "type": "git",
75
- "url": "git+https://github.com/nasyx-rakeeb/react-native-frame-capture.git"
76
- },
77
- "author": "Nasyx Rakeeb <nasyxrakeeb2@gmail.com> (https://github.com/nasyx-rakeeb)",
78
- "license": "MIT",
79
- "bugs": {
80
- "url": "https://github.com/nasyx-rakeeb/react-native-frame-capture/issues"
81
- },
82
- "homepage": "https://github.com/nasyx-rakeeb/react-native-frame-capture#readme",
83
- "publishConfig": {
84
- "registry": "https://registry.npmjs.org/"
85
- },
86
- "devDependencies": {
87
- "@commitlint/config-conventional": "^19.8.1",
88
- "@eslint/compat": "^1.3.2",
89
- "@eslint/eslintrc": "^3.3.1",
90
- "@eslint/js": "^9.35.0",
91
- "@evilmartians/lefthook": "^1.12.3",
92
- "@expo/config-plugins": "^9.0.0",
93
- "@react-native-community/cli": "20.0.1",
94
- "@react-native/babel-preset": "0.81.1",
95
- "@react-native/eslint-config": "^0.81.1",
96
- "@release-it/conventional-changelog": "^10.0.1",
97
- "@types/jest": "^29.5.14",
98
- "@types/react": "^19.1.0",
99
- "commitlint": "^19.8.1",
100
- "del-cli": "^6.0.0",
101
- "eslint": "^9.35.0",
102
- "eslint-config-prettier": "^10.1.8",
103
- "eslint-plugin-prettier": "^5.5.4",
104
- "jest": "^29.7.0",
105
- "prettier": "^3.6.2",
106
- "react": "19.1.0",
107
- "react-native": "0.81.1",
108
- "react-native-builder-bob": "^0.40.13",
109
- "release-it": "^19.0.4",
110
- "turbo": "^2.5.6",
111
- "typescript": "^5.9.2"
112
- },
113
- "peerDependencies": {
114
- "expo": "*",
115
- "react": "*",
116
- "react-native": "*"
117
- },
118
- "peerDependenciesMeta": {
119
- "expo": {
120
- "optional": true
121
- }
122
- },
123
- "workspaces": [
124
- "example"
125
- ],
126
- "packageManager": "yarn@3.6.1",
127
- "jest": {
128
- "preset": "react-native",
129
- "modulePathIgnorePatterns": [
130
- "<rootDir>/example/node_modules",
131
- "<rootDir>/lib/"
132
- ]
133
- },
134
- "commitlint": {
135
- "extends": [
136
- "@commitlint/config-conventional"
137
- ]
138
- },
139
- "release-it": {
140
- "git": {
141
- "commitMessage": "chore: release ${version}",
142
- "tagName": "v${version}"
143
- },
144
- "npm": {
145
- "publish": true
146
- },
147
- "github": {
148
- "release": true
149
- },
150
- "plugins": {
151
- "@release-it/conventional-changelog": {
152
- "preset": {
153
- "name": "angular"
154
- }
155
- }
156
- }
157
- },
158
- "prettier": {
159
- "quoteProps": "consistent",
160
- "singleQuote": true,
161
- "tabWidth": 2,
162
- "trailingComma": "es5",
163
- "useTabs": false
164
- },
165
- "react-native-builder-bob": {
166
- "source": "src",
167
- "output": "lib",
168
- "targets": [
169
- [
170
- "module",
171
- {
172
- "esm": true
173
- }
174
- ],
175
- [
176
- "typescript",
177
- {
178
- "project": "tsconfig.build.json"
179
- }
180
- ]
181
- ]
182
- },
183
- "codegenConfig": {
184
- "name": "FrameCaptureSpec",
185
- "type": "modules",
186
- "jsSrcsDir": "src",
187
- "android": {
188
- "javaPackageName": "com.framecapture"
189
- }
190
- },
191
- "create-react-native-library": {
192
- "languages": "kotlin-objc",
193
- "type": "turbo-module",
194
- "version": "0.54.8"
195
- }
196
- }
1
+ {
2
+ "name": "react-native-frame-capture",
3
+ "version": "1.1.0",
4
+ "description": "Reliable screen capture for React Native Android. Capture frames at intervals with customizable overlays and storage options.",
5
+ "main": "./lib/module/index.js",
6
+ "types": "./lib/typescript/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.tsx",
10
+ "types": "./lib/typescript/src/index.d.ts",
11
+ "default": "./lib/module/index.js"
12
+ },
13
+ "./app.plugin.js": "./app.plugin.js",
14
+ "./package.json": "./package.json"
15
+ },
16
+ "files": [
17
+ "src",
18
+ "lib",
19
+ "android",
20
+ "ios",
21
+ "cpp",
22
+ "plugin/build",
23
+ "*.podspec",
24
+ "react-native.config.js",
25
+ "app.plugin.js",
26
+ "!ios/build",
27
+ "!android/build",
28
+ "!android/gradle",
29
+ "!android/gradlew",
30
+ "!android/gradlew.bat",
31
+ "!android/local.properties",
32
+ "!**/__tests__",
33
+ "!**/__fixtures__",
34
+ "!**/__mocks__",
35
+ "!**/.*"
36
+ ],
37
+ "scripts": {
38
+ "example": "yarn workspace react-native-frame-capture-example",
39
+ "test": "jest --passWithNoTests",
40
+ "typecheck": "tsc",
41
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
42
+ "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
43
+ "prepare": "bob build",
44
+ "release": "release-it --only-version",
45
+ "run-dev": "cd example/android && gradlew clean && cd ../../ && yarn prepare && yarn example android"
46
+ },
47
+ "keywords": [
48
+ "react-native",
49
+ "android",
50
+ "screen-capture",
51
+ "frame-capture",
52
+ "screenshot",
53
+ "screen-recording",
54
+ "interval-capture",
55
+ "media-projection",
56
+ "turbo-module",
57
+ "view-shot",
58
+ "react-native-view-shot",
59
+ "expo",
60
+ "capture",
61
+ "frame",
62
+ "screen",
63
+ "recording",
64
+ "fps",
65
+ "foreground-service",
66
+ "overlay",
67
+ "watermark",
68
+ "image-overlay",
69
+ "text-overlay",
70
+ "kotlin",
71
+ "javascript",
72
+ "typescript",
73
+ "background-capture",
74
+ "periodic-capture"
75
+ ],
76
+ "repository": {
77
+ "type": "git",
78
+ "url": "git+https://github.com/nasyx-rakeeb/react-native-frame-capture.git"
79
+ },
80
+ "author": "Nasyx Rakeeb <nasyxrakeeb2@gmail.com> (https://github.com/nasyx-rakeeb)",
81
+ "license": "MIT",
82
+ "bugs": {
83
+ "url": "https://github.com/nasyx-rakeeb/react-native-frame-capture/issues"
84
+ },
85
+ "homepage": "https://github.com/nasyx-rakeeb/react-native-frame-capture#readme",
86
+ "publishConfig": {
87
+ "registry": "https://registry.npmjs.org/"
88
+ },
89
+ "devDependencies": {
90
+ "@commitlint/config-conventional": "^19.8.1",
91
+ "@eslint/compat": "^1.3.2",
92
+ "@eslint/eslintrc": "^3.3.1",
93
+ "@eslint/js": "^9.35.0",
94
+ "@evilmartians/lefthook": "^1.12.3",
95
+ "@expo/config-plugins": "^9.0.0",
96
+ "@react-native-community/cli": "20.0.1",
97
+ "@react-native/babel-preset": "0.81.1",
98
+ "@react-native/eslint-config": "^0.81.1",
99
+ "@release-it/conventional-changelog": "^10.0.1",
100
+ "@types/jest": "^29.5.14",
101
+ "@types/react": "^19.1.0",
102
+ "commitlint": "^19.8.1",
103
+ "del-cli": "^6.0.0",
104
+ "eslint": "^9.35.0",
105
+ "eslint-config-prettier": "^10.1.8",
106
+ "eslint-plugin-prettier": "^5.5.4",
107
+ "jest": "^29.7.0",
108
+ "prettier": "^3.6.2",
109
+ "react": "19.1.0",
110
+ "react-native": "0.81.1",
111
+ "react-native-builder-bob": "^0.40.13",
112
+ "release-it": "^19.0.4",
113
+ "turbo": "^2.5.6",
114
+ "typescript": "^5.9.2"
115
+ },
116
+ "peerDependencies": {
117
+ "expo": "*",
118
+ "react": "*",
119
+ "react-native": "*"
120
+ },
121
+ "peerDependenciesMeta": {
122
+ "expo": {
123
+ "optional": true
124
+ }
125
+ },
126
+ "workspaces": [
127
+ "example"
128
+ ],
129
+ "packageManager": "yarn@3.6.1",
130
+ "jest": {
131
+ "preset": "react-native",
132
+ "modulePathIgnorePatterns": [
133
+ "<rootDir>/example/node_modules",
134
+ "<rootDir>/lib/"
135
+ ]
136
+ },
137
+ "commitlint": {
138
+ "extends": [
139
+ "@commitlint/config-conventional"
140
+ ]
141
+ },
142
+ "release-it": {
143
+ "git": {
144
+ "commitMessage": "chore: release ${version}",
145
+ "tagName": "v${version}"
146
+ },
147
+ "npm": {
148
+ "publish": true
149
+ },
150
+ "github": {
151
+ "release": true
152
+ },
153
+ "plugins": {
154
+ "@release-it/conventional-changelog": {
155
+ "preset": {
156
+ "name": "angular"
157
+ }
158
+ }
159
+ }
160
+ },
161
+ "prettier": {
162
+ "quoteProps": "consistent",
163
+ "singleQuote": true,
164
+ "tabWidth": 2,
165
+ "trailingComma": "es5",
166
+ "useTabs": false
167
+ },
168
+ "react-native-builder-bob": {
169
+ "source": "src",
170
+ "output": "lib",
171
+ "targets": [
172
+ [
173
+ "module",
174
+ {
175
+ "esm": true
176
+ }
177
+ ],
178
+ [
179
+ "typescript",
180
+ {
181
+ "project": "tsconfig.build.json"
182
+ }
183
+ ]
184
+ ]
185
+ },
186
+ "codegenConfig": {
187
+ "name": "FrameCaptureSpec",
188
+ "type": "modules",
189
+ "jsSrcsDir": "src",
190
+ "android": {
191
+ "javaPackageName": "com.framecapture"
192
+ }
193
+ },
194
+ "create-react-native-library": {
195
+ "languages": "kotlin-objc",
196
+ "type": "turbo-module",
197
+ "version": "0.54.8"
198
+ }
199
+ }
@@ -56,6 +56,13 @@ export type OverlayErrorEvent = {
56
56
  message: string;
57
57
  };
58
58
 
59
+ export type ChangeDetectedEvent = {
60
+ changePercent: number;
61
+ threshold: number;
62
+ captured: boolean;
63
+ timeSinceLastCapture: number;
64
+ };
65
+
59
66
  /**
60
67
  * TurboModule specification for FrameCapture
61
68
  * Defines the native methods implemented in Kotlin
@@ -70,6 +77,7 @@ export interface Spec extends TurboModule {
70
77
  readonly onCapturePause: EventEmitter<CapturePauseEvent>;
71
78
  readonly onCaptureResume: EventEmitter<CaptureResumeEvent>;
72
79
  readonly onOverlayError: EventEmitter<OverlayErrorEvent>;
80
+ readonly onChangeDetected: EventEmitter<ChangeDetectedEvent>;
73
81
 
74
82
  // Methods
75
83
  requestPermission(): Promise<string>;
package/src/constants.ts CHANGED
@@ -67,3 +67,48 @@ export const MAX_QUALITY = 100;
67
67
  * @deprecated Use advanced.storage.warningThreshold in CaptureOptions instead
68
68
  */
69
69
  export const STORAGE_WARNING_THRESHOLD = 100 * 1024 * 1024; // 100MB
70
+
71
+ // =============================================================================
72
+ // Change Detection Mode Constants
73
+ // =============================================================================
74
+
75
+ /**
76
+ * Default change detection threshold (percentage of pixels changed)
77
+ */
78
+ export const DEFAULT_CHANGE_THRESHOLD = 5;
79
+
80
+ /**
81
+ * Minimum change detection threshold
82
+ */
83
+ export const MIN_CHANGE_THRESHOLD = 0;
84
+
85
+ /**
86
+ * Maximum change detection threshold
87
+ */
88
+ export const MAX_CHANGE_THRESHOLD = 100;
89
+
90
+ /**
91
+ * Default minimum interval between captures in change detection mode (ms)
92
+ */
93
+ export const DEFAULT_CHANGE_MIN_INTERVAL = 500;
94
+
95
+ /**
96
+ * Default maximum interval between captures in change detection mode (ms)
97
+ * 0 means disabled - no forced captures when screen is static
98
+ */
99
+ export const DEFAULT_CHANGE_MAX_INTERVAL = 0;
100
+
101
+ /**
102
+ * Default sample rate for change detection (every Nth pixel)
103
+ */
104
+ export const DEFAULT_CHANGE_SAMPLE_RATE = 16;
105
+
106
+ /**
107
+ * Minimum sample rate (1 = every pixel)
108
+ */
109
+ export const MIN_CHANGE_SAMPLE_RATE = 1;
110
+
111
+ /**
112
+ * Maximum sample rate
113
+ */
114
+ export const MAX_CHANGE_SAMPLE_RATE = 64;
package/src/normalize.ts CHANGED
@@ -4,13 +4,22 @@
4
4
  * @module normalize
5
5
  */
6
6
 
7
- import type { CaptureOptions } from './types';
7
+ import type { CaptureOptions, CaptureMode } from './types';
8
8
 
9
9
  /**
10
10
  * Flat options structure expected by native code
11
11
  */
12
12
  export interface NativeCaptureOptions {
13
- interval: number;
13
+ // Capture mode
14
+ captureMode: CaptureMode;
15
+ interval?: number;
16
+ // Change detection options (flat)
17
+ changeThreshold?: number;
18
+ changeMinInterval?: number;
19
+ changeMaxInterval?: number;
20
+ changeSampleRate?: number;
21
+ changeDetectionRegion?: any;
22
+ // Image options
14
23
  quality: number;
15
24
  format: 'png' | 'jpeg';
16
25
  saveFrames?: boolean;
@@ -48,10 +57,21 @@ export function normalizeOptions(
48
57
  const { capture, image, storage, performance, notification, overlays } =
49
58
  options;
50
59
 
60
+ const captureMode = capture.mode || 'interval';
61
+ const changeDetection = capture.changeDetection;
62
+
51
63
  return {
52
- // Capture config
64
+ // Capture mode
65
+ captureMode,
53
66
  interval: capture.interval,
54
67
 
68
+ // Change detection config (flattened)
69
+ changeThreshold: changeDetection?.threshold,
70
+ changeMinInterval: changeDetection?.minInterval,
71
+ changeMaxInterval: changeDetection?.maxInterval,
72
+ changeSampleRate: changeDetection?.sampleRate,
73
+ changeDetectionRegion: changeDetection?.detectionRegion,
74
+
55
75
  // Image config
56
76
  quality: image.quality,
57
77
  format: image.format,
package/src/types.ts CHANGED
@@ -50,6 +50,7 @@ export enum CaptureEventType {
50
50
  CAPTURE_PAUSE = 'onCapturePause',
51
51
  CAPTURE_RESUME = 'onCaptureResume',
52
52
  OVERLAY_ERROR = 'onOverlayError',
53
+ CHANGE_DETECTED = 'onChangeDetected',
53
54
  }
54
55
 
55
56
  // ============================================================================
@@ -71,6 +72,11 @@ export type PositionPreset =
71
72
  | 'bottom-right'
72
73
  | 'center';
73
74
 
75
+ /**
76
+ * Capture mode type
77
+ */
78
+ export type CaptureMode = 'interval' | 'change-detection';
79
+
74
80
  // ============================================================================
75
81
  // Capture Configuration
76
82
  // ============================================================================
@@ -124,12 +130,32 @@ export interface NotificationOptions {
124
130
  showResumeAction?: boolean;
125
131
  }
126
132
 
133
+ /**
134
+ * Change detection configuration
135
+ */
136
+ export interface ChangeDetectionConfig {
137
+ /** Minimum percentage of pixels that must change to trigger capture (0-100) */
138
+ threshold: number;
139
+ /** Minimum milliseconds between captures even with rapid changes (default: 500) */
140
+ minInterval?: number;
141
+ /** Maximum milliseconds between captures regardless of changes (0 = disabled, default: 0) */
142
+ maxInterval?: number;
143
+ /** Pixel sampling rate for performance (1 = every pixel, 16 = every 16th pixel, default: 16) */
144
+ sampleRate?: number;
145
+ /** Region of interest for change detection (default: full screen) */
146
+ detectionRegion?: CaptureRegion;
147
+ }
148
+
127
149
  /**
128
150
  * Capture behavior configuration
129
151
  */
130
152
  export interface CaptureConfig {
131
- /** Milliseconds between captures (100-60000) */
132
- interval: number;
153
+ /** Capture mode: 'interval' or 'change-detection' (default: 'interval') */
154
+ mode?: CaptureMode;
155
+ /** Milliseconds between captures (100-60000) - required when mode is 'interval' */
156
+ interval?: number;
157
+ /** Change detection settings - required when mode is 'change-detection' */
158
+ changeDetection?: ChangeDetectionConfig;
133
159
  }
134
160
 
135
161
  /**
@@ -300,6 +326,7 @@ import type {
300
326
  CapturePauseEvent,
301
327
  CaptureResumeEvent,
302
328
  OverlayErrorEvent,
329
+ ChangeDetectedEvent,
303
330
  } from './NativeFrameCapture';
304
331
 
305
332
  export type {
@@ -311,6 +338,7 @@ export type {
311
338
  CapturePauseEvent,
312
339
  CaptureResumeEvent,
313
340
  OverlayErrorEvent,
341
+ ChangeDetectedEvent,
314
342
  };
315
343
 
316
344
  /**