@teardown/cli 1.2.38 → 2.0.41
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/bin/teardown.js +11 -1
- package/package.json +77 -57
- package/src/cli/commands/init.ts +254 -0
- package/src/cli/commands/plugins.ts +93 -0
- package/src/cli/commands/prebuild.ts +168 -0
- package/src/cli/commands/run.ts +727 -0
- package/src/cli/commands/start.ts +87 -0
- package/src/cli/commands/validate.ts +62 -0
- package/src/cli/index.ts +59 -0
- package/src/config/index.ts +45 -0
- package/src/config/loader.ts +366 -0
- package/src/config/schema.ts +235 -0
- package/src/config/types.ts +322 -0
- package/src/index.ts +177 -0
- package/src/pipeline/cache.ts +179 -0
- package/src/pipeline/index.ts +10 -0
- package/src/pipeline/stages.ts +692 -0
- package/src/plugins/base.ts +370 -0
- package/src/plugins/capabilities/biometrics.ts +64 -0
- package/src/plugins/capabilities/bluetooth.ts +86 -0
- package/src/plugins/capabilities/calendar.ts +57 -0
- package/src/plugins/capabilities/camera.ts +77 -0
- package/src/plugins/capabilities/contacts.ts +57 -0
- package/src/plugins/capabilities/deep-linking.ts +124 -0
- package/src/plugins/capabilities/firebase.ts +138 -0
- package/src/plugins/capabilities/index.ts +96 -0
- package/src/plugins/capabilities/location.ts +87 -0
- package/src/plugins/capabilities/photo-library.ts +80 -0
- package/src/plugins/capabilities/push-notifications.ts +98 -0
- package/src/plugins/capabilities/sign-in-with-apple.ts +53 -0
- package/src/plugins/context.ts +220 -0
- package/src/plugins/index.ts +26 -0
- package/src/plugins/resolver.ts +321 -0
- package/src/templates/generator.ts +507 -0
- package/src/templates/index.ts +9 -0
- package/src/templates/paths.ts +25 -0
- package/src/transformers/android/gradle.ts +400 -0
- package/src/transformers/android/index.ts +19 -0
- package/src/transformers/android/manifest.ts +506 -0
- package/src/transformers/index.ts +39 -0
- package/src/transformers/ios/entitlements.ts +283 -0
- package/src/transformers/ios/index.ts +10 -0
- package/src/transformers/ios/pbxproj.ts +267 -0
- package/src/transformers/ios/plist.ts +198 -0
- package/src/utils/fs.ts +429 -0
- package/src/utils/index.ts +21 -0
- package/src/utils/logger.ts +203 -0
- package/templates/.gitignore +63 -0
- package/templates/Gemfile +3 -0
- package/templates/android/app/build.gradle.kts +97 -0
- package/templates/android/app/proguard-rules.pro +10 -0
- package/templates/android/app/src/main/AndroidManifest.xml +26 -0
- package/templates/android/app/src/main/java/com/appname/MainActivity.kt +22 -0
- package/templates/android/app/src/main/java/com/appname/MainApplication.kt +44 -0
- package/templates/android/app/src/main/res/values/strings.xml +3 -0
- package/templates/android/app/src/main/res/values/styles.xml +7 -0
- package/templates/android/build.gradle.kts +44 -0
- package/templates/android/gradle.properties +39 -0
- package/templates/android/settings.gradle.kts +12 -0
- package/templates/babel.config.js +15 -0
- package/templates/index.js +7 -0
- package/templates/ios/.xcode.env +11 -0
- package/templates/ios/AppName/AppDelegate.swift +25 -0
- package/templates/ios/AppName/AppName-Bridging-Header.h +4 -0
- package/templates/ios/AppName/AppName.entitlements +6 -0
- package/templates/ios/AppName/Images.xcassets/AppIcon.appiconset/Contents.json +35 -0
- package/templates/ios/AppName/Images.xcassets/Contents.json +6 -0
- package/templates/ios/AppName/Info.plist +49 -0
- package/templates/ios/AppName/LaunchScreen.storyboard +38 -0
- package/templates/ios/AppName.xcodeproj/project.pbxproj +402 -0
- package/templates/ios/AppName.xcodeproj/xcshareddata/xcschemes/AppName.xcscheme +78 -0
- package/templates/ios/Podfile +35 -0
- package/templates/metro.config.js +41 -0
- package/templates/package.json +57 -0
- package/templates/react-native.config.js +8 -0
- package/templates/src/app/index.tsx +34 -0
- package/templates/src/assets/fonts/.gitkeep +1 -0
- package/templates/src/assets/images/.gitkeep +1 -0
- package/templates/src/components/ui/accordion.tsx +114 -0
- package/templates/src/components/ui/avatar.tsx +75 -0
- package/templates/src/components/ui/button.tsx +93 -0
- package/templates/src/components/ui/card.tsx +120 -0
- package/templates/src/components/ui/checkbox.tsx +133 -0
- package/templates/src/components/ui/chip.tsx +95 -0
- package/templates/src/components/ui/dialog.tsx +134 -0
- package/templates/src/components/ui/divider.tsx +67 -0
- package/templates/src/components/ui/error-view.tsx +82 -0
- package/templates/src/components/ui/form-field.tsx +101 -0
- package/templates/src/components/ui/index.ts +100 -0
- package/templates/src/components/ui/popover.tsx +92 -0
- package/templates/src/components/ui/pressable-feedback.tsx +88 -0
- package/templates/src/components/ui/radio-group.tsx +153 -0
- package/templates/src/components/ui/scroll-shadow.tsx +108 -0
- package/templates/src/components/ui/select.tsx +165 -0
- package/templates/src/components/ui/skeleton-group.tsx +97 -0
- package/templates/src/components/ui/skeleton.tsx +87 -0
- package/templates/src/components/ui/spinner.tsx +87 -0
- package/templates/src/components/ui/surface.tsx +95 -0
- package/templates/src/components/ui/switch.tsx +124 -0
- package/templates/src/components/ui/tabs.tsx +154 -0
- package/templates/src/components/ui/text-field.tsx +106 -0
- package/templates/src/components/ui/toast.tsx +129 -0
- package/templates/src/contexts/.gitkeep +2 -0
- package/templates/src/core/clients/api/api.client.ts +113 -0
- package/templates/src/core/clients/api/index.ts +1 -0
- package/templates/src/core/clients/storage/index.ts +1 -0
- package/templates/src/core/clients/storage/storage.client.ts +121 -0
- package/templates/src/core/constants/index.ts +19 -0
- package/templates/src/core/core.ts +40 -0
- package/templates/src/core/index.ts +10 -0
- package/templates/src/global.css +87 -0
- package/templates/src/hooks/index.ts +6 -0
- package/templates/src/hooks/use-debounce.ts +23 -0
- package/templates/src/hooks/use-mounted.ts +21 -0
- package/templates/src/index.ts +28 -0
- package/templates/src/lib/index.ts +5 -0
- package/templates/src/lib/utils.ts +115 -0
- package/templates/src/modules/.gitkeep +6 -0
- package/templates/src/navigation/index.ts +8 -0
- package/templates/src/navigation/navigation-provider.tsx +36 -0
- package/templates/src/navigation/router.tsx +137 -0
- package/templates/src/providers/app.provider.tsx +29 -0
- package/templates/src/providers/index.ts +5 -0
- package/templates/src/routes/(tabs)/_layout.tsx +42 -0
- package/templates/src/routes/(tabs)/explore.tsx +161 -0
- package/templates/src/routes/(tabs)/home.tsx +138 -0
- package/templates/src/routes/(tabs)/profile.tsx +151 -0
- package/templates/src/routes/_layout.tsx +18 -0
- package/templates/src/routes/settings.tsx +194 -0
- package/templates/src/screens/auth/index.ts +6 -0
- package/templates/src/screens/auth/login.tsx +165 -0
- package/templates/src/screens/auth/register.tsx +203 -0
- package/templates/src/screens/home.tsx +204 -0
- package/templates/src/screens/index.ts +17 -0
- package/templates/src/screens/profile.tsx +210 -0
- package/templates/src/screens/settings.tsx +216 -0
- package/templates/src/screens/welcome.tsx +101 -0
- package/templates/src/styles/index.ts +103 -0
- package/templates/src/types/common.ts +71 -0
- package/templates/src/types/index.ts +5 -0
- package/templates/tsconfig.json +14 -0
- package/README.md +0 -15
- package/assets/favicon.ico +0 -0
- package/dist/commands/dev/dev.js +0 -55
- package/dist/commands/init/init-teardown.js +0 -26
- package/dist/index.js +0 -20
- package/dist/modules/dev/dev-menu/keyboard-handler.js +0 -138
- package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.js +0 -105
- package/dist/modules/dev/dev-server/cdp/cdp.adapter.js +0 -12
- package/dist/modules/dev/dev-server/cdp/index.js +0 -18
- package/dist/modules/dev/dev-server/cdp/types.js +0 -2
- package/dist/modules/dev/dev-server/dev-server-checker.js +0 -72
- package/dist/modules/dev/dev-server/dev-server.js +0 -269
- package/dist/modules/dev/dev-server/inspector/device.event-reporter.js +0 -165
- package/dist/modules/dev/dev-server/inspector/device.js +0 -577
- package/dist/modules/dev/dev-server/inspector/inspector.js +0 -204
- package/dist/modules/dev/dev-server/inspector/types.js +0 -2
- package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.js +0 -61
- package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.js +0 -64
- package/dist/modules/dev/dev-server/plugins/devtools.plugin.js +0 -50
- package/dist/modules/dev/dev-server/plugins/favicon.plugin.js +0 -19
- package/dist/modules/dev/dev-server/plugins/multipart.plugin.js +0 -62
- package/dist/modules/dev/dev-server/plugins/systrace.plugin.js +0 -28
- package/dist/modules/dev/dev-server/plugins/types.js +0 -2
- package/dist/modules/dev/dev-server/plugins/wss/index.js +0 -19
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.js +0 -66
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.js +0 -128
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.js +0 -75
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.js +0 -198
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.js +0 -120
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.js +0 -357
- package/dist/modules/dev/dev-server/plugins/wss/types.js +0 -2
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.js +0 -57
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.js +0 -26
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.js +0 -46
- package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.js +0 -55
- package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.js +0 -36
- package/dist/modules/dev/dev-server/sybmolicate/types.js +0 -2
- package/dist/modules/dev/terminal/base.terminal.reporter.js +0 -78
- package/dist/modules/dev/terminal/terminal.reporter.js +0 -76
- package/dist/modules/dev/types.js +0 -2
- package/dist/modules/dev/utils/log.js +0 -73
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
2
|
+
import type { AndroidIntentFilter, ProcessedAppConfig } from "../../config/types";
|
|
3
|
+
import type { PluginContext } from "../../plugins/context";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Android Manifest structure (parsed from XML)
|
|
7
|
+
*/
|
|
8
|
+
export interface AndroidManifestXml {
|
|
9
|
+
"?xml"?: {
|
|
10
|
+
"@_version": string;
|
|
11
|
+
"@_encoding": string;
|
|
12
|
+
};
|
|
13
|
+
manifest: {
|
|
14
|
+
"@_xmlns:android": string;
|
|
15
|
+
"@_package": string;
|
|
16
|
+
"uses-permission"?: AndroidPermission[];
|
|
17
|
+
"uses-feature"?: AndroidFeature[];
|
|
18
|
+
queries?: AndroidQueries;
|
|
19
|
+
application: AndroidApplication;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AndroidPermission {
|
|
24
|
+
"@_android:name": string;
|
|
25
|
+
"@_android:maxSdkVersion"?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AndroidFeature {
|
|
29
|
+
"@_android:name": string;
|
|
30
|
+
"@_android:required"?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AndroidQueries {
|
|
34
|
+
package?: Array<{ "@_android:name": string }>;
|
|
35
|
+
intent?: AndroidIntentXml[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface AndroidApplication {
|
|
39
|
+
"@_android:name"?: string;
|
|
40
|
+
"@_android:label"?: string;
|
|
41
|
+
"@_android:icon"?: string;
|
|
42
|
+
"@_android:roundIcon"?: string;
|
|
43
|
+
"@_android:allowBackup"?: string;
|
|
44
|
+
"@_android:theme"?: string;
|
|
45
|
+
"@_android:networkSecurityConfig"?: string;
|
|
46
|
+
"@_android:supportsRtl"?: string;
|
|
47
|
+
activity?: AndroidActivityXml[];
|
|
48
|
+
service?: AndroidServiceXml[];
|
|
49
|
+
receiver?: AndroidReceiverXml[];
|
|
50
|
+
provider?: AndroidProviderXml[];
|
|
51
|
+
"meta-data"?: AndroidMetaData[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface AndroidActivityXml {
|
|
55
|
+
"@_android:name": string;
|
|
56
|
+
"@_android:label"?: string;
|
|
57
|
+
"@_android:exported"?: string;
|
|
58
|
+
"@_android:launchMode"?: string;
|
|
59
|
+
"@_android:screenOrientation"?: string;
|
|
60
|
+
"@_android:configChanges"?: string;
|
|
61
|
+
"@_android:windowSoftInputMode"?: string;
|
|
62
|
+
"@_android:theme"?: string;
|
|
63
|
+
"intent-filter"?: AndroidIntentFilterXml[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface AndroidIntentFilterXml {
|
|
67
|
+
"@_android:autoVerify"?: string;
|
|
68
|
+
action?: Array<{ "@_android:name": string }>;
|
|
69
|
+
category?: Array<{ "@_android:name": string }>;
|
|
70
|
+
data?: Array<{
|
|
71
|
+
"@_android:scheme"?: string;
|
|
72
|
+
"@_android:host"?: string;
|
|
73
|
+
"@_android:pathPrefix"?: string;
|
|
74
|
+
"@_android:path"?: string;
|
|
75
|
+
}>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface AndroidIntentXml {
|
|
79
|
+
action?: Array<{ "@_android:name": string }>;
|
|
80
|
+
data?: Array<{
|
|
81
|
+
"@_android:scheme"?: string;
|
|
82
|
+
"@_android:host"?: string;
|
|
83
|
+
}>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface AndroidServiceXml {
|
|
87
|
+
"@_android:name": string;
|
|
88
|
+
"@_android:exported"?: string;
|
|
89
|
+
"@_android:permission"?: string;
|
|
90
|
+
"intent-filter"?: AndroidIntentFilterXml[];
|
|
91
|
+
"meta-data"?: AndroidMetaData[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface AndroidReceiverXml {
|
|
95
|
+
"@_android:name": string;
|
|
96
|
+
"@_android:exported"?: string;
|
|
97
|
+
"intent-filter"?: AndroidIntentFilterXml[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface AndroidProviderXml {
|
|
101
|
+
"@_android:name": string;
|
|
102
|
+
"@_android:authorities": string;
|
|
103
|
+
"@_android:exported"?: string;
|
|
104
|
+
"@_android:grantUriPermissions"?: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface AndroidMetaData {
|
|
108
|
+
"@_android:name": string;
|
|
109
|
+
"@_android:value"?: string;
|
|
110
|
+
"@_android:resource"?: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* XML Parser configuration
|
|
115
|
+
*/
|
|
116
|
+
const parserOptions = {
|
|
117
|
+
ignoreAttributes: false,
|
|
118
|
+
attributeNamePrefix: "@_",
|
|
119
|
+
allowBooleanAttributes: true,
|
|
120
|
+
parseAttributeValue: false,
|
|
121
|
+
trimValues: true,
|
|
122
|
+
isArray: (name: string) => {
|
|
123
|
+
// These elements should always be treated as arrays even if there's only one
|
|
124
|
+
const alwaysArray = [
|
|
125
|
+
"uses-permission",
|
|
126
|
+
"uses-feature",
|
|
127
|
+
"activity",
|
|
128
|
+
"service",
|
|
129
|
+
"receiver",
|
|
130
|
+
"provider",
|
|
131
|
+
"meta-data",
|
|
132
|
+
"intent-filter",
|
|
133
|
+
"action",
|
|
134
|
+
"category",
|
|
135
|
+
"data",
|
|
136
|
+
"package",
|
|
137
|
+
"intent",
|
|
138
|
+
];
|
|
139
|
+
return alwaysArray.includes(name);
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const builderOptions = {
|
|
144
|
+
ignoreAttributes: false,
|
|
145
|
+
attributeNamePrefix: "@_",
|
|
146
|
+
format: true,
|
|
147
|
+
indentBy: " ",
|
|
148
|
+
suppressEmptyNode: false,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Android Manifest transformer
|
|
153
|
+
*/
|
|
154
|
+
export class AndroidManifestTransformer {
|
|
155
|
+
private parser: XMLParser;
|
|
156
|
+
private builder: XMLBuilder;
|
|
157
|
+
|
|
158
|
+
constructor() {
|
|
159
|
+
this.parser = new XMLParser(parserOptions);
|
|
160
|
+
this.builder = new XMLBuilder(builderOptions);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Transform the AndroidManifest.xml with configuration
|
|
165
|
+
*/
|
|
166
|
+
async transform(context: PluginContext, config: ProcessedAppConfig): Promise<void> {
|
|
167
|
+
const { fs, log, androidPaths } = context;
|
|
168
|
+
|
|
169
|
+
log.debug("Transforming AndroidManifest.xml...");
|
|
170
|
+
|
|
171
|
+
let content: string;
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
content = await fs.readFile(androidPaths.manifest);
|
|
175
|
+
} catch {
|
|
176
|
+
log.warn("AndroidManifest.xml not found, creating default manifest");
|
|
177
|
+
content = this.createDefaultManifest(config);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Parse XML
|
|
181
|
+
const manifest = this.parser.parse(content) as AndroidManifestXml;
|
|
182
|
+
|
|
183
|
+
// Apply transformations
|
|
184
|
+
this.applyPackageName(manifest, config);
|
|
185
|
+
this.applyPermissions(manifest, config);
|
|
186
|
+
this.applyFeatures(manifest, config);
|
|
187
|
+
this.applyMetadata(manifest, config);
|
|
188
|
+
this.applyIntentFilters(manifest, config);
|
|
189
|
+
|
|
190
|
+
// Build XML
|
|
191
|
+
const xmlHeader = '<?xml version="1.0" encoding="utf-8"?>\n';
|
|
192
|
+
const updatedContent = xmlHeader + this.builder.build(manifest);
|
|
193
|
+
|
|
194
|
+
// Write back
|
|
195
|
+
await fs.writeFile(androidPaths.manifest, updatedContent);
|
|
196
|
+
|
|
197
|
+
log.debug("AndroidManifest.xml transformation complete");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Create default AndroidManifest.xml
|
|
202
|
+
*/
|
|
203
|
+
private createDefaultManifest(config: ProcessedAppConfig): string {
|
|
204
|
+
const packageName = config.android?.packageName ?? "com.example.app";
|
|
205
|
+
|
|
206
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
207
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
208
|
+
package="${packageName}">
|
|
209
|
+
|
|
210
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
211
|
+
|
|
212
|
+
<application
|
|
213
|
+
android:name=".MainApplication"
|
|
214
|
+
android:label="@string/app_name"
|
|
215
|
+
android:icon="@mipmap/ic_launcher"
|
|
216
|
+
android:roundIcon="@mipmap/ic_launcher_round"
|
|
217
|
+
android:allowBackup="false"
|
|
218
|
+
android:theme="@style/AppTheme">
|
|
219
|
+
<activity
|
|
220
|
+
android:name=".MainActivity"
|
|
221
|
+
android:label="@string/app_name"
|
|
222
|
+
android:exported="true"
|
|
223
|
+
android:launchMode="singleTask"
|
|
224
|
+
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode"
|
|
225
|
+
android:windowSoftInputMode="adjustResize">
|
|
226
|
+
<intent-filter>
|
|
227
|
+
<action android:name="android.intent.action.MAIN" />
|
|
228
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
229
|
+
</intent-filter>
|
|
230
|
+
</activity>
|
|
231
|
+
</application>
|
|
232
|
+
</manifest>`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Apply package name to manifest
|
|
237
|
+
*/
|
|
238
|
+
private applyPackageName(manifest: AndroidManifestXml, config: ProcessedAppConfig): void {
|
|
239
|
+
if (config.android?.packageName) {
|
|
240
|
+
manifest.manifest["@_package"] = config.android.packageName;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Apply permissions to manifest
|
|
246
|
+
*/
|
|
247
|
+
private applyPermissions(manifest: AndroidManifestXml, config: ProcessedAppConfig): void {
|
|
248
|
+
if (!manifest.manifest["uses-permission"]) {
|
|
249
|
+
manifest.manifest["uses-permission"] = [];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Normalize to array if XML parser returned a single object
|
|
253
|
+
if (!Array.isArray(manifest.manifest["uses-permission"])) {
|
|
254
|
+
manifest.manifest["uses-permission"] = [manifest.manifest["uses-permission"]];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const existingPermissions = new Set(manifest.manifest["uses-permission"].map((p) => p["@_android:name"]));
|
|
258
|
+
|
|
259
|
+
for (const permission of config.resolvedAndroidPermissions) {
|
|
260
|
+
if (!existingPermissions.has(permission)) {
|
|
261
|
+
manifest.manifest["uses-permission"].push({
|
|
262
|
+
"@_android:name": permission,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Apply features to manifest
|
|
270
|
+
*/
|
|
271
|
+
private applyFeatures(manifest: AndroidManifestXml, config: ProcessedAppConfig): void {
|
|
272
|
+
if (!manifest.manifest["uses-feature"]) {
|
|
273
|
+
manifest.manifest["uses-feature"] = [];
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Normalize to array if XML parser returned a single object
|
|
277
|
+
if (!Array.isArray(manifest.manifest["uses-feature"])) {
|
|
278
|
+
manifest.manifest["uses-feature"] = [manifest.manifest["uses-feature"]];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const existingFeatures = new Set(manifest.manifest["uses-feature"].map((f) => f["@_android:name"]));
|
|
282
|
+
|
|
283
|
+
for (const feature of config.resolvedAndroidFeatures) {
|
|
284
|
+
if (!existingFeatures.has(feature)) {
|
|
285
|
+
manifest.manifest["uses-feature"].push({
|
|
286
|
+
"@_android:name": feature,
|
|
287
|
+
"@_android:required": "true",
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Apply metadata to manifest
|
|
295
|
+
*/
|
|
296
|
+
private applyMetadata(manifest: AndroidManifestXml, config: ProcessedAppConfig): void {
|
|
297
|
+
if (!manifest.manifest.application["meta-data"]) {
|
|
298
|
+
manifest.manifest.application["meta-data"] = [];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Normalize to array if XML parser returned a single object
|
|
302
|
+
if (!Array.isArray(manifest.manifest.application["meta-data"])) {
|
|
303
|
+
manifest.manifest.application["meta-data"] = [manifest.manifest.application["meta-data"]];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const existingMetadata = new Map(manifest.manifest.application["meta-data"].map((m) => [m["@_android:name"], m]));
|
|
307
|
+
|
|
308
|
+
for (const [key, value] of Object.entries(config.resolvedAndroidMetadata)) {
|
|
309
|
+
if (existingMetadata.has(key)) {
|
|
310
|
+
// Update existing
|
|
311
|
+
const existing = existingMetadata.get(key)!;
|
|
312
|
+
existing["@_android:value"] = value;
|
|
313
|
+
} else {
|
|
314
|
+
// Add new
|
|
315
|
+
manifest.manifest.application["meta-data"].push({
|
|
316
|
+
"@_android:name": key,
|
|
317
|
+
"@_android:value": value,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Apply intent filters to MainActivity
|
|
325
|
+
*/
|
|
326
|
+
private applyIntentFilters(manifest: AndroidManifestXml, config: ProcessedAppConfig): void {
|
|
327
|
+
if (config.resolvedIntentFilters.length === 0 && !config.scheme) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Find MainActivity
|
|
332
|
+
let activities = manifest.manifest.application.activity;
|
|
333
|
+
if (!activities) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Normalize to array if XML parser returned a single object
|
|
338
|
+
if (!Array.isArray(activities)) {
|
|
339
|
+
activities = [activities];
|
|
340
|
+
manifest.manifest.application.activity = activities;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (activities.length === 0) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const mainActivity = activities.find((a) => a["@_android:name"] === ".MainActivity") || activities[0];
|
|
348
|
+
|
|
349
|
+
if (!mainActivity["intent-filter"]) {
|
|
350
|
+
mainActivity["intent-filter"] = [];
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Normalize to array if XML parser returned a single object
|
|
354
|
+
if (!Array.isArray(mainActivity["intent-filter"])) {
|
|
355
|
+
mainActivity["intent-filter"] = [mainActivity["intent-filter"]];
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Add custom scheme if configured
|
|
359
|
+
if (config.scheme) {
|
|
360
|
+
const schemeFilter: AndroidIntentFilterXml = {
|
|
361
|
+
action: [{ "@_android:name": "android.intent.action.VIEW" }],
|
|
362
|
+
category: [
|
|
363
|
+
{ "@_android:name": "android.intent.category.DEFAULT" },
|
|
364
|
+
{ "@_android:name": "android.intent.category.BROWSABLE" },
|
|
365
|
+
],
|
|
366
|
+
data: [{ "@_android:scheme": config.scheme }],
|
|
367
|
+
};
|
|
368
|
+
mainActivity["intent-filter"].push(schemeFilter);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Add resolved intent filters
|
|
372
|
+
for (const filter of config.resolvedIntentFilters) {
|
|
373
|
+
const xmlFilter = this.convertIntentFilter(filter);
|
|
374
|
+
mainActivity["intent-filter"].push(xmlFilter);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Convert internal intent filter to XML format
|
|
380
|
+
*/
|
|
381
|
+
private convertIntentFilter(filter: AndroidIntentFilter): AndroidIntentFilterXml {
|
|
382
|
+
const xmlFilter: AndroidIntentFilterXml = {};
|
|
383
|
+
|
|
384
|
+
if (filter.autoVerify) {
|
|
385
|
+
xmlFilter["@_android:autoVerify"] = "true";
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (filter.actions.length > 0) {
|
|
389
|
+
xmlFilter.action = filter.actions.map((a) => ({ "@_android:name": a }));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (filter.categories.length > 0) {
|
|
393
|
+
xmlFilter.category = filter.categories.map((c) => ({ "@_android:name": c }));
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (filter.data && filter.data.length > 0) {
|
|
397
|
+
xmlFilter.data = filter.data.map((d) => ({
|
|
398
|
+
...(d.scheme && { "@_android:scheme": d.scheme }),
|
|
399
|
+
...(d.host && { "@_android:host": d.host }),
|
|
400
|
+
...(d.pathPrefix && { "@_android:pathPrefix": d.pathPrefix }),
|
|
401
|
+
}));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return xmlFilter;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Add a permission to an existing manifest
|
|
409
|
+
*/
|
|
410
|
+
static addPermission(manifest: AndroidManifestXml, permission: string): void {
|
|
411
|
+
if (!manifest.manifest["uses-permission"]) {
|
|
412
|
+
manifest.manifest["uses-permission"] = [];
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Normalize to array if XML parser returned a single object
|
|
416
|
+
if (!Array.isArray(manifest.manifest["uses-permission"])) {
|
|
417
|
+
manifest.manifest["uses-permission"] = [manifest.manifest["uses-permission"]];
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const exists = manifest.manifest["uses-permission"].some((p) => p["@_android:name"] === permission);
|
|
421
|
+
|
|
422
|
+
if (!exists) {
|
|
423
|
+
manifest.manifest["uses-permission"].push({
|
|
424
|
+
"@_android:name": permission,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Add a feature to an existing manifest
|
|
431
|
+
*/
|
|
432
|
+
static addFeature(manifest: AndroidManifestXml, feature: string, required = true): void {
|
|
433
|
+
if (!manifest.manifest["uses-feature"]) {
|
|
434
|
+
manifest.manifest["uses-feature"] = [];
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Normalize to array if XML parser returned a single object
|
|
438
|
+
if (!Array.isArray(manifest.manifest["uses-feature"])) {
|
|
439
|
+
manifest.manifest["uses-feature"] = [manifest.manifest["uses-feature"]];
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const exists = manifest.manifest["uses-feature"].some((f) => f["@_android:name"] === feature);
|
|
443
|
+
|
|
444
|
+
if (!exists) {
|
|
445
|
+
manifest.manifest["uses-feature"].push({
|
|
446
|
+
"@_android:name": feature,
|
|
447
|
+
"@_android:required": String(required),
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Add metadata to the application
|
|
454
|
+
*/
|
|
455
|
+
static addMetadata(manifest: AndroidManifestXml, name: string, value: string, isResource = false): void {
|
|
456
|
+
if (!manifest.manifest.application["meta-data"]) {
|
|
457
|
+
manifest.manifest.application["meta-data"] = [];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Normalize to array if XML parser returned a single object
|
|
461
|
+
if (!Array.isArray(manifest.manifest.application["meta-data"])) {
|
|
462
|
+
manifest.manifest.application["meta-data"] = [manifest.manifest.application["meta-data"]];
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const existing = manifest.manifest.application["meta-data"].find((m) => m["@_android:name"] === name);
|
|
466
|
+
|
|
467
|
+
if (existing) {
|
|
468
|
+
if (isResource) {
|
|
469
|
+
existing["@_android:resource"] = value;
|
|
470
|
+
delete existing["@_android:value"];
|
|
471
|
+
} else {
|
|
472
|
+
existing["@_android:value"] = value;
|
|
473
|
+
delete existing["@_android:resource"];
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
const metadata: AndroidMetaData = {
|
|
477
|
+
"@_android:name": name,
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
if (isResource) {
|
|
481
|
+
metadata["@_android:resource"] = value;
|
|
482
|
+
} else {
|
|
483
|
+
metadata["@_android:value"] = value;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
manifest.manifest.application["meta-data"].push(metadata);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Parse an AndroidManifest.xml file
|
|
492
|
+
*/
|
|
493
|
+
static parse(content: string): AndroidManifestXml {
|
|
494
|
+
const parser = new XMLParser(parserOptions);
|
|
495
|
+
return parser.parse(content) as AndroidManifestXml;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Build XML from AndroidManifest object
|
|
500
|
+
*/
|
|
501
|
+
static build(manifest: AndroidManifestXml): string {
|
|
502
|
+
const builder = new XMLBuilder(builderOptions);
|
|
503
|
+
const xmlHeader = '<?xml version="1.0" encoding="utf-8"?>\n';
|
|
504
|
+
return xmlHeader + builder.build(manifest);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File transformers for Teardown Launchpad
|
|
3
|
+
*
|
|
4
|
+
* Provides transformers for native iOS and Android files
|
|
5
|
+
* including plist, entitlements, Xcode project, manifest, and Gradle.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
AndroidActivityXml,
|
|
10
|
+
AndroidApplication,
|
|
11
|
+
AndroidFeature,
|
|
12
|
+
AndroidIntentFilterXml,
|
|
13
|
+
AndroidManifestXml,
|
|
14
|
+
AndroidMetaData,
|
|
15
|
+
AndroidPermission,
|
|
16
|
+
AndroidProviderXml,
|
|
17
|
+
AndroidQueries,
|
|
18
|
+
AndroidReceiverXml,
|
|
19
|
+
AndroidServiceXml,
|
|
20
|
+
} from "./android";
|
|
21
|
+
// Android transformers
|
|
22
|
+
export {
|
|
23
|
+
AndroidManifestTransformer,
|
|
24
|
+
GradleTransformer,
|
|
25
|
+
StringsTransformer,
|
|
26
|
+
} from "./android";
|
|
27
|
+
export type {
|
|
28
|
+
BuildSettings,
|
|
29
|
+
CFBundleURLType,
|
|
30
|
+
EntitlementsContent,
|
|
31
|
+
InfoPlistContent,
|
|
32
|
+
} from "./ios";
|
|
33
|
+
// iOS transformers
|
|
34
|
+
export {
|
|
35
|
+
EntitlementsTransformer,
|
|
36
|
+
PbxprojTransformer,
|
|
37
|
+
PlistTransformer,
|
|
38
|
+
XcodeProjectManipulator,
|
|
39
|
+
} from "./ios";
|