expo-privacy-image 1.0.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.
- package/.eslintrc.js +5 -0
- package/README.md +139 -0
- package/android/build.gradle +18 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/privacyimage/PrivacyImageModule.kt +83 -0
- package/build/PrivacyImageModule.d.ts +7 -0
- package/build/PrivacyImageModule.d.ts.map +1 -0
- package/build/PrivacyImageModule.js +4 -0
- package/build/PrivacyImageModule.js.map +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +10 -0
- package/ios/AppLifecycleDelegate.swift +46 -0
- package/ios/PrivacyImage.podspec +28 -0
- package/ios/PrivacyImageModule.swift +20 -0
- package/package.json +41 -0
- package/plugin/build/index.d.ts +6 -0
- package/plugin/build/index.js +71 -0
- package/plugin/src/index.ts +49 -0
- package/plugin/tsconfig.json +9 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
- package/src/PrivacyImageModule.ts +8 -0
- package/src/index.ts +5 -0
- package/tsconfig.json +9 -0
package/.eslintrc.js
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# expo-privacy-image
|
|
2
|
+
|
|
3
|
+
A React Native module that overlays a privacy image on the screen whenever the app goes to the background — preventing sensitive content from appearing in the app switcher (iOS) or recent apps (Android).
|
|
4
|
+
|
|
5
|
+
Built with [Expo Modules](https://docs.expo.dev/modules/overview/).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Platform support
|
|
10
|
+
|
|
11
|
+
| Android | iOS |
|
|
12
|
+
| ------- | --- |
|
|
13
|
+
| ✅ | ✅ |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install expo-privacy-image
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
or
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
yarn add expo-privacy-image
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Setup
|
|
32
|
+
|
|
33
|
+
### Expo managed / bare workflow (with `expo prebuild`)
|
|
34
|
+
|
|
35
|
+
Add the plugin to your `app.config.ts` (or `app.json`) and point it at your privacy image:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
// app.config.ts
|
|
39
|
+
export default {
|
|
40
|
+
plugins: [
|
|
41
|
+
[
|
|
42
|
+
"expo-privacy-image",
|
|
43
|
+
{
|
|
44
|
+
imagePath: "./assets/images/privacy.png",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Then run prebuild to apply the native changes:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
npx expo prebuild
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The plugin automatically:
|
|
58
|
+
- **Android** — copies the image to `android/app/src/main/res/drawable/privacy_image.png`
|
|
59
|
+
- **iOS** — adds the image as `PrivacyImage.imageset` inside `Images.xcassets`
|
|
60
|
+
|
|
61
|
+
### Bare React Native (manual setup)
|
|
62
|
+
|
|
63
|
+
Ensure [`expo-modules-core`](https://docs.expo.dev/bare/installing-expo-modules/) is installed before proceeding — it is required for autolinking to work.
|
|
64
|
+
|
|
65
|
+
**Android**
|
|
66
|
+
|
|
67
|
+
Copy your privacy image to:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
android/app/src/main/res/drawable/privacy_image.png
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**iOS**
|
|
74
|
+
|
|
75
|
+
Create the imageset directory and add your image:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
ios/<ProjectName>/Images.xcassets/PrivacyImage.imageset/
|
|
79
|
+
privacy_image.png
|
|
80
|
+
Contents.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`Contents.json` should contain:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"images": [
|
|
88
|
+
{ "idiom": "universal", "filename": "privacy_image.png", "scale": "1x" }
|
|
89
|
+
],
|
|
90
|
+
"info": { "version": 1, "author": "xcode" }
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Then run:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
npx pod-install
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Usage
|
|
103
|
+
|
|
104
|
+
Call `usePrivacyImage()` once — typically at the root of your app or inside a top-level component. Once called, the module is permanently enabled for the lifetime of the app session.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { usePrivacyImage } from "expo-privacy-image";
|
|
108
|
+
|
|
109
|
+
export default function App() {
|
|
110
|
+
usePrivacyImage();
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
// ...
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
When the app moves to the background, the image you configured is shown as a full-screen overlay. It is removed automatically when the app returns to the foreground.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## API
|
|
123
|
+
|
|
124
|
+
### `usePrivacyImage(): void`
|
|
125
|
+
|
|
126
|
+
Enables the privacy overlay for the current app session. Safe to call multiple times — subsequent calls are no-ops.
|
|
127
|
+
|
|
128
|
+
| Parameter | Type | Description |
|
|
129
|
+
| --------- | ---- | ----------- |
|
|
130
|
+
| — | — | No parameters |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Requirements
|
|
135
|
+
|
|
136
|
+
- React Native ≥ 0.71
|
|
137
|
+
- expo
|
|
138
|
+
- iOS ≥ 15.1
|
|
139
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
id 'com.android.library'
|
|
3
|
+
id 'expo-module-gradle-plugin'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
group = 'expo.modules.privacyimage'
|
|
7
|
+
version = '0.1.0'
|
|
8
|
+
|
|
9
|
+
android {
|
|
10
|
+
namespace "expo.modules.privacyimage"
|
|
11
|
+
defaultConfig {
|
|
12
|
+
versionCode 1
|
|
13
|
+
versionName "0.1.0"
|
|
14
|
+
}
|
|
15
|
+
lintOptions {
|
|
16
|
+
abortOnError false
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
package expo.modules.privacyimage
|
|
2
|
+
|
|
3
|
+
import android.view.ViewGroup
|
|
4
|
+
import android.widget.ImageView
|
|
5
|
+
import expo.modules.kotlin.exception.Exceptions
|
|
6
|
+
import expo.modules.kotlin.modules.Module
|
|
7
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
8
|
+
|
|
9
|
+
class PrivacyImageModule : Module() {
|
|
10
|
+
|
|
11
|
+
private var isPrivacyEnabled: Boolean = false
|
|
12
|
+
// Each module class must implement the definition function. The definition consists of components
|
|
13
|
+
// that describes the module's functionality and behavior.
|
|
14
|
+
// See https://docs.expo.dev/modules/module-api for more details about available components.
|
|
15
|
+
private val safeCurrentActivity
|
|
16
|
+
get() = appContext.currentActivity
|
|
17
|
+
private val currentActivity
|
|
18
|
+
get() = safeCurrentActivity ?: throw Exceptions.MissingActivity()
|
|
19
|
+
|
|
20
|
+
private var overlayView: ImageView? = null
|
|
21
|
+
|
|
22
|
+
private fun showOverlay() {
|
|
23
|
+
currentActivity.runOnUiThread {
|
|
24
|
+
if (overlayView != null) return@runOnUiThread
|
|
25
|
+
|
|
26
|
+
val overlay =
|
|
27
|
+
ImageView(currentActivity).apply {
|
|
28
|
+
val drawableId =
|
|
29
|
+
currentActivity.resources.getIdentifier(
|
|
30
|
+
"privacy_image",
|
|
31
|
+
"drawable",
|
|
32
|
+
currentActivity.packageName
|
|
33
|
+
)
|
|
34
|
+
setImageResource(drawableId)
|
|
35
|
+
scaleType = ImageView.ScaleType.CENTER_CROP
|
|
36
|
+
layoutParams =
|
|
37
|
+
ViewGroup.LayoutParams(
|
|
38
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
39
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
val rootView = currentActivity.window.decorView as ViewGroup
|
|
44
|
+
rootView.addView(overlay)
|
|
45
|
+
overlayView = overlay
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private fun hideOverlay() {
|
|
50
|
+
currentActivity.runOnUiThread {
|
|
51
|
+
val rootView = currentActivity.window.decorView as ViewGroup
|
|
52
|
+
overlayView?.let {
|
|
53
|
+
rootView.removeView(it)
|
|
54
|
+
overlayView = null
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override fun definition() = ModuleDefinition {
|
|
60
|
+
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a
|
|
61
|
+
// string as an argument.
|
|
62
|
+
// Can be inferred from module's class name, but it's recommended to set it explicitly for
|
|
63
|
+
// clarity.
|
|
64
|
+
// The module will be accessible from `requireNativeModule('PrivacyImage')` in JavaScript.
|
|
65
|
+
Name("PrivacyImage")
|
|
66
|
+
|
|
67
|
+
Function("usePrivacyImage") { isPrivacyEnabled = true }
|
|
68
|
+
|
|
69
|
+
OnActivityEntersBackground {
|
|
70
|
+
// Show privacy overlay
|
|
71
|
+
if (!isPrivacyEnabled) return@OnActivityEntersBackground
|
|
72
|
+
|
|
73
|
+
showOverlay()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
OnActivityEntersForeground {
|
|
77
|
+
// Remove privacy overlay
|
|
78
|
+
if (!isPrivacyEnabled) return@OnActivityEntersForeground
|
|
79
|
+
|
|
80
|
+
hideOverlay()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrivacyImageModule.d.ts","sourceRoot":"","sources":["../src/PrivacyImageModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,OAAO,kBAAmB,SAAQ,YAAY;IACnD,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;;AAGD,wBAAuE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrivacyImageModule.js","sourceRoot":"","sources":["../src/PrivacyImageModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAMzD,yDAAyD;AACzD,eAAe,mBAAmB,CAAqB,cAAc,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo\";\n\ndeclare class PrivacyImageModule extends NativeModule {\n usePrivacyImage: () => void;\n}\n\n// This call loads the native module object from the JSI.\nexport default requireNativeModule<PrivacyImageModule>(\"PrivacyImage\");\n"]}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,SAE9B"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AAEtD,MAAM,UAAU,eAAe;IAC7B,kBAAkB,CAAC,eAAe,EAAE,CAAC;AACvC,CAAC","sourcesContent":["import PrivacyImageModule from \"./PrivacyImageModule\";\n\nexport function usePrivacyImage() {\n PrivacyImageModule.usePrivacyImage();\n}\n"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import ExpoModulesCore
|
|
2
|
+
|
|
3
|
+
public class AppLifecycleDelegate: ExpoAppDelegateSubscriber {
|
|
4
|
+
|
|
5
|
+
private var overlayView: UIImageView?
|
|
6
|
+
|
|
7
|
+
public func applicationWillResignActive(_ application: UIApplication) {
|
|
8
|
+
guard PrivacyImageModule.isPrivacyEnabled else { return }
|
|
9
|
+
self.showOverlay()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public func applicationDidBecomeActive(_ application: UIApplication) {
|
|
13
|
+
guard PrivacyImageModule.isPrivacyEnabled else { return }
|
|
14
|
+
self.hideOverlay()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private func showOverlay() {
|
|
18
|
+
DispatchQueue.main.async {
|
|
19
|
+
guard self.overlayView == nil,
|
|
20
|
+
let window = self.getKeyWindow()
|
|
21
|
+
else { return }
|
|
22
|
+
|
|
23
|
+
let overlay = UIImageView(frame: window.bounds)
|
|
24
|
+
overlay.image = UIImage(named: "PrivacyImage")
|
|
25
|
+
overlay.contentMode = .scaleAspectFill
|
|
26
|
+
overlay.tag = 999
|
|
27
|
+
|
|
28
|
+
window.addSubview(overlay)
|
|
29
|
+
self.overlayView = overlay
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private func hideOverlay() {
|
|
34
|
+
DispatchQueue.main.async {
|
|
35
|
+
self.overlayView?.removeFromSuperview()
|
|
36
|
+
self.overlayView = nil
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private func getKeyWindow() -> UIWindow? {
|
|
41
|
+
UIApplication.shared.connectedScenes
|
|
42
|
+
.compactMap { $0 as? UIWindowScene }
|
|
43
|
+
.flatMap { $0.windows }
|
|
44
|
+
.first { $0.isKeyWindow }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'PrivacyImage'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.description = package['description']
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.homepage = package['homepage']
|
|
13
|
+
s.platforms = {
|
|
14
|
+
:ios => '15.1',
|
|
15
|
+
}
|
|
16
|
+
s.swift_version = '5.9'
|
|
17
|
+
s.source = { git: 'https://github.com/ntphu1808/expo-privacy-image' }
|
|
18
|
+
s.static_framework = true
|
|
19
|
+
|
|
20
|
+
s.dependency 'ExpoModulesCore'
|
|
21
|
+
|
|
22
|
+
# Swift/Objective-C compatibility
|
|
23
|
+
s.pod_target_xcconfig = {
|
|
24
|
+
'DEFINES_MODULE' => 'YES',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
|
|
28
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import ExpoModulesCore
|
|
2
|
+
|
|
3
|
+
public class PrivacyImageModule: Module {
|
|
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.
|
|
7
|
+
|
|
8
|
+
static var isPrivacyEnabled: Bool = false
|
|
9
|
+
|
|
10
|
+
public func definition() -> ModuleDefinition {
|
|
11
|
+
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
|
|
12
|
+
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
|
|
13
|
+
// The module will be accessible from `requireNativeModule('PrivacyImage')` in JavaScript.
|
|
14
|
+
Name("PrivacyImage")
|
|
15
|
+
|
|
16
|
+
Function("usePrivacyImage") {
|
|
17
|
+
PrivacyImageModule.isPrivacyEnabled = true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "expo-privacy-image",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Overlays a privacy image on the screen when the app goes to the background.",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"types": "build/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "expo-module build",
|
|
9
|
+
"clean": "expo-module clean",
|
|
10
|
+
"lint": "expo-module lint",
|
|
11
|
+
"test": "expo-module test",
|
|
12
|
+
"prepare": "expo-module prepare",
|
|
13
|
+
"prepublishOnly": "expo-module prepublishOnly",
|
|
14
|
+
"expo-module": "expo-module"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react-native",
|
|
18
|
+
"expo",
|
|
19
|
+
"expo-privacy-image",
|
|
20
|
+
"PrivacyImage"
|
|
21
|
+
],
|
|
22
|
+
"repository": "https://github.com/ntphu1808/expo-privacy-image",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/ntphu1808/expo-privacy-image/issues"
|
|
25
|
+
},
|
|
26
|
+
"author": "Nguyen Tran Phu <ntphu081995@gmail.com> (https://github.com/ntphu1808)",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"homepage": "https://github.com/ntphu1808/expo-privacy-image#readme",
|
|
29
|
+
"dependencies": {},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/react": "~19.1.1",
|
|
32
|
+
"expo-module-scripts": "^55.0.2",
|
|
33
|
+
"expo": "^55.0.14",
|
|
34
|
+
"react-native": "0.82.1"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"expo": "*",
|
|
38
|
+
"react": "*",
|
|
39
|
+
"react-native": "*"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
// plugins/withPrivacyImage.ts
|
|
37
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const withPrivacyImage = (config, { imagePath }) => {
|
|
41
|
+
// Android - copy to res/drawable
|
|
42
|
+
config = (0, config_plugins_1.withDangerousMod)(config, [
|
|
43
|
+
"android",
|
|
44
|
+
async (config) => {
|
|
45
|
+
const src = path.resolve(config.modRequest.projectRoot, imagePath);
|
|
46
|
+
const dest = path.join(config.modRequest.platformProjectRoot, "app/src/main/res/drawable/privacy_image.png");
|
|
47
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
48
|
+
fs.copyFileSync(src, dest);
|
|
49
|
+
return config;
|
|
50
|
+
},
|
|
51
|
+
]);
|
|
52
|
+
// iOS - copy into Images.xcassets as an imageset so UIImage(named:) works
|
|
53
|
+
config = (0, config_plugins_1.withDangerousMod)(config, [
|
|
54
|
+
"ios",
|
|
55
|
+
async (config) => {
|
|
56
|
+
const src = path.resolve(config.modRequest.projectRoot, imagePath);
|
|
57
|
+
const projectName = config.modRequest.projectName;
|
|
58
|
+
const imagesetDir = path.join(config.modRequest.platformProjectRoot, projectName, "Images.xcassets", "PrivacyImage.imageset");
|
|
59
|
+
fs.mkdirSync(imagesetDir, { recursive: true });
|
|
60
|
+
fs.copyFileSync(src, path.join(imagesetDir, "privacy_image.png"));
|
|
61
|
+
const contents = {
|
|
62
|
+
images: [{ idiom: "universal", filename: "privacy_image.png", scale: "1x" }],
|
|
63
|
+
info: { version: 1, author: "xcode" },
|
|
64
|
+
};
|
|
65
|
+
fs.writeFileSync(path.join(imagesetDir, "Contents.json"), JSON.stringify(contents, null, 2));
|
|
66
|
+
return config;
|
|
67
|
+
},
|
|
68
|
+
]);
|
|
69
|
+
return config;
|
|
70
|
+
};
|
|
71
|
+
exports.default = withPrivacyImage;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// plugins/withPrivacyImage.ts
|
|
2
|
+
import { ConfigPlugin, withDangerousMod } from "expo/config-plugins";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
|
|
6
|
+
type PrivacyImageProps = {
|
|
7
|
+
imagePath: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const withPrivacyImage: ConfigPlugin<PrivacyImageProps> = (config, { imagePath }) => {
|
|
11
|
+
// Android - copy to res/drawable
|
|
12
|
+
config = withDangerousMod(config, [
|
|
13
|
+
"android",
|
|
14
|
+
async (config) => {
|
|
15
|
+
const src = path.resolve(config.modRequest.projectRoot, imagePath);
|
|
16
|
+
const dest = path.join(config.modRequest.platformProjectRoot, "app/src/main/res/drawable/privacy_image.png");
|
|
17
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
18
|
+
fs.copyFileSync(src, dest);
|
|
19
|
+
return config;
|
|
20
|
+
},
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
// iOS - copy into Images.xcassets as an imageset so UIImage(named:) works
|
|
24
|
+
config = withDangerousMod(config, [
|
|
25
|
+
"ios",
|
|
26
|
+
async (config) => {
|
|
27
|
+
const src = path.resolve(config.modRequest.projectRoot, imagePath);
|
|
28
|
+
const projectName = config.modRequest.projectName!;
|
|
29
|
+
const imagesetDir = path.join(
|
|
30
|
+
config.modRequest.platformProjectRoot,
|
|
31
|
+
projectName,
|
|
32
|
+
"Images.xcassets",
|
|
33
|
+
"PrivacyImage.imageset",
|
|
34
|
+
);
|
|
35
|
+
fs.mkdirSync(imagesetDir, { recursive: true });
|
|
36
|
+
fs.copyFileSync(src, path.join(imagesetDir, "privacy_image.png"));
|
|
37
|
+
const contents = {
|
|
38
|
+
images: [{ idiom: "universal", filename: "privacy_image.png", scale: "1x" }],
|
|
39
|
+
info: { version: 1, author: "xcode" },
|
|
40
|
+
};
|
|
41
|
+
fs.writeFileSync(path.join(imagesetDir, "Contents.json"), JSON.stringify(contents, null, 2));
|
|
42
|
+
return config;
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
return config;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default withPrivacyImage;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/index.ts"],"version":"5.9.3"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NativeModule, requireNativeModule } from "expo";
|
|
2
|
+
|
|
3
|
+
declare class PrivacyImageModule extends NativeModule {
|
|
4
|
+
usePrivacyImage: () => void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// This call loads the native module object from the JSI.
|
|
8
|
+
export default requireNativeModule<PrivacyImageModule>("PrivacyImage");
|
package/src/index.ts
ADDED
package/tsconfig.json
ADDED