codeplay-common 2.1.47 → 2.1.48
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/.gitattributes +2 -2
- package/LICENSE +21 -21
- package/README.md +11 -11
- package/files/buildCodeplay/add-splash-screen-1.6.js +248 -248
- package/files/buildCodeplay/codeplayBeforeBuild-5.3.js +1369 -1369
- package/files/buildCodeplay/ios-emi-admob-modification.js +52 -52
- package/files/buildCodeplay/manifestModification.js +33 -33
- package/files/buildCodeplay/modify-plugin-xml.js +36 -36
- package/files/buildCodeplay/packageidBaseModification-1.4.js +402 -402
- package/files/buildCodeplay/remove-force-kotlin-disable.js +45 -0
- package/files/buildCodeplay/setSplashAnimation-1.2.js +170 -170
- package/files/buildCodeplay/splashxml/codeplay_splashScreen.xml +11 -11
- package/files/finalrelease +835 -835
- package/files/iap-install-2.js +145 -145
- package/files/ionic.config.json +6 -6
- package/package.json +16 -16
- package/scripts/sync-files.js +86 -86
- package/scripts/uninstall.js +77 -77
|
@@ -1,403 +1,403 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Adds user permissions to AndroidManifest.xml if not already present
|
|
7
|
-
* based on capacitor.config.json appId matching.
|
|
8
|
-
*
|
|
9
|
-
* @param {string} targetAppId - appId you want to match
|
|
10
|
-
* @param {string[]} permissionsToAdd - permission tags to insert
|
|
11
|
-
*/
|
|
12
|
-
function addAndroidPermissions(permissionsToAdd) {
|
|
13
|
-
try {
|
|
14
|
-
|
|
15
|
-
if (!Array.isArray(permissionsToAdd) || permissionsToAdd.length === 0) {
|
|
16
|
-
console.log("ℹ️ No permissions to add");
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// read capacitor.config.json
|
|
21
|
-
const configPath = path.join(process.cwd(), 'capacitor.config.json');
|
|
22
|
-
if (!fs.existsSync(configPath)) {
|
|
23
|
-
console.error(`❌ capacitor.config.json not found at: ${configPath}`);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const rawData = fs.readFileSync(configPath, 'utf8');
|
|
28
|
-
const config = JSON.parse(rawData);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const androidManifestPath = path.join(
|
|
33
|
-
process.cwd(),
|
|
34
|
-
'android',
|
|
35
|
-
'app',
|
|
36
|
-
'src',
|
|
37
|
-
'main',
|
|
38
|
-
'AndroidManifest.xml'
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
if (!fs.existsSync(androidManifestPath)) {
|
|
42
|
-
console.error(`❌ AndroidManifest.xml not found at: ${androidManifestPath}`);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
let manifestContent = fs.readFileSync(androidManifestPath, 'utf8');
|
|
47
|
-
let updated = false;
|
|
48
|
-
|
|
49
|
-
permissionsToAdd.forEach(permission => {
|
|
50
|
-
if (!manifestContent.includes(permission)) {
|
|
51
|
-
console.log(`🔧 Adding permission: ${permission}`);
|
|
52
|
-
manifestContent = manifestContent.replace(
|
|
53
|
-
'</manifest>',
|
|
54
|
-
` ${permission}\n</manifest>`
|
|
55
|
-
);
|
|
56
|
-
updated = true;
|
|
57
|
-
} else {
|
|
58
|
-
console.log(`ℹ️ Permission already exists: ${permission}`);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
if (updated) {
|
|
63
|
-
fs.writeFileSync(androidManifestPath, manifestContent, 'utf8');
|
|
64
|
-
console.log('✅ AndroidManifest.xml updated successfully.');
|
|
65
|
-
} else {
|
|
66
|
-
console.log('✅ All required permissions already present.');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
} catch (error) {
|
|
70
|
-
console.error(`❌ Error: ${error.message}`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const addFavIconCode=()=>{
|
|
77
|
-
const htmlFilePath = path.join(process.cwd(), 'src', 'index.html');
|
|
78
|
-
|
|
79
|
-
if (fs.existsSync(htmlFilePath)) {
|
|
80
|
-
let htmlContent = fs.readFileSync(htmlFilePath, 'utf8');
|
|
81
|
-
|
|
82
|
-
const faviconTag = '<link rel="icon" href="data:;base64,iVBORw0KGgo=">';
|
|
83
|
-
|
|
84
|
-
if (!htmlContent.includes(faviconTag)) {
|
|
85
|
-
const headOpenTag = '<head>';
|
|
86
|
-
const headIndex = htmlContent.indexOf(headOpenTag);
|
|
87
|
-
|
|
88
|
-
if (headIndex !== -1) {
|
|
89
|
-
const insertPos = headIndex + headOpenTag.length;
|
|
90
|
-
htmlContent =
|
|
91
|
-
htmlContent.slice(0, insertPos) +
|
|
92
|
-
`\n ${faviconTag}` +
|
|
93
|
-
htmlContent.slice(insertPos);
|
|
94
|
-
|
|
95
|
-
fs.writeFileSync(htmlFilePath, htmlContent, 'utf8');
|
|
96
|
-
console.log(`✅ Favicon link added successfully to index.html`);
|
|
97
|
-
} else {
|
|
98
|
-
console.error('❌ <head> tag not found in index.html');
|
|
99
|
-
}
|
|
100
|
-
} else {
|
|
101
|
-
console.log('ℹ️ Favicon link already exists in index.html');
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
console.error(`❌ index.html not found at: ${htmlFilePath}`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const appJssmallModifications=()=>{
|
|
110
|
-
|
|
111
|
-
const appJsPath = path.join(process.cwd(), 'src', 'js', 'app.js');
|
|
112
|
-
|
|
113
|
-
if (fs.existsSync(appJsPath)) {
|
|
114
|
-
let appJsContent = fs.readFileSync(appJsPath, 'utf8');
|
|
115
|
-
|
|
116
|
-
// 1. ensure iosOverlaysWebView is true
|
|
117
|
-
if (/iosOverlaysWebView\s*:\s*false/.test(appJsContent)) {
|
|
118
|
-
appJsContent = appJsContent.replace(/iosOverlaysWebView\s*:\s*false/, 'iosOverlaysWebView: true');
|
|
119
|
-
console.log('✅ iosOverlaysWebView changed to true');
|
|
120
|
-
} else if (!/iosOverlaysWebView\s*:/.test(appJsContent)) {
|
|
121
|
-
// add if missing
|
|
122
|
-
appJsContent = appJsContent.replace(
|
|
123
|
-
/statusbar\s*:\s*\{/,
|
|
124
|
-
`statusbar: {\n iosOverlaysWebView: true,`
|
|
125
|
-
);
|
|
126
|
-
console.log('✅ iosOverlaysWebView added');
|
|
127
|
-
} else {
|
|
128
|
-
console.log('ℹ️ iosOverlaysWebView already true');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 2. ensure androidOverlaysWebView is true
|
|
132
|
-
if (/androidOverlaysWebView\s*:\s*false/.test(appJsContent)) {
|
|
133
|
-
appJsContent = appJsContent.replace(/androidOverlaysWebView\s*:\s*false/, 'androidOverlaysWebView: true');
|
|
134
|
-
console.log('✅ androidOverlaysWebView changed to true');
|
|
135
|
-
} else if (!/androidOverlaysWebView\s*:/.test(appJsContent)) {
|
|
136
|
-
// add if missing
|
|
137
|
-
appJsContent = appJsContent.replace(
|
|
138
|
-
/statusbar\s*:\s*\{/,
|
|
139
|
-
`statusbar: {\n androidOverlaysWebView: true,`
|
|
140
|
-
);
|
|
141
|
-
console.log('✅ androidOverlaysWebView added');
|
|
142
|
-
} else {
|
|
143
|
-
console.log('ℹ️ androidOverlaysWebView already true');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// 3. change theme
|
|
147
|
-
const themeRegex = /theme\s*:\s*['"]auto['"]/;
|
|
148
|
-
if (themeRegex.test(appJsContent)) {
|
|
149
|
-
appJsContent = appJsContent.replace(themeRegex, `theme: 'md'`);
|
|
150
|
-
console.log('✅ theme changed to md');
|
|
151
|
-
} else {
|
|
152
|
-
console.log('ℹ️ theme: auto not found, no changes made');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
fs.writeFileSync(appJsPath, appJsContent, 'utf8');
|
|
156
|
-
console.log('✅ app.js updated successfully');
|
|
157
|
-
} else {
|
|
158
|
-
console.error(`❌ src/js/app.js not found at: ${appJsPath}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const ensureTouchHighlightDisabled = () => {
|
|
164
|
-
const appJsPath = path.join(process.cwd(), 'src', 'js', 'app.js');
|
|
165
|
-
|
|
166
|
-
if (!fs.existsSync(appJsPath)) {
|
|
167
|
-
console.error(`❌ src/js/app.js not found at: ${appJsPath}`);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
let content = fs.readFileSync(appJsPath, 'utf8');
|
|
172
|
-
|
|
173
|
-
// 1️⃣ If explicitly true → change to false
|
|
174
|
-
if (/touchHighlightElements\s*:\s*true/.test(content)) {
|
|
175
|
-
content = content.replace(
|
|
176
|
-
/touchHighlightElements\s*:\s*true/g,
|
|
177
|
-
'touchHighlightElements: false'
|
|
178
|
-
);
|
|
179
|
-
console.log('✅ Updated touchHighlightElements true → false');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// 2️⃣ If already false → skip
|
|
183
|
-
else if (/touchHighlightElements\s*:\s*false/.test(content)) {
|
|
184
|
-
console.log('ℹ️ touchHighlightElements already false');
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// 3️⃣ If touch block exists → add inside it
|
|
189
|
-
else if (/touch\s*:\s*\{/.test(content)) {
|
|
190
|
-
content = content.replace(
|
|
191
|
-
/(touch\s*:\s*\{)/,
|
|
192
|
-
`$1\n touchHighlightElements: false,`
|
|
193
|
-
);
|
|
194
|
-
console.log('✅ Added touchHighlightElements inside existing touch block');
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// 4️⃣ If no touch block → create one
|
|
198
|
-
else {
|
|
199
|
-
content = content.replace(
|
|
200
|
-
/new Framework7\s*\(\s*\{/,
|
|
201
|
-
`new Framework7({\n touch: {\n touchHighlightElements: false\n },`
|
|
202
|
-
);
|
|
203
|
-
console.log('✅ Created new touch block with touchHighlightElements:false');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
fs.writeFileSync(appJsPath, content, 'utf8');
|
|
207
|
-
console.log('✅ Done updating app.js');
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const replaceKeyboardSet=()=>{
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const appJsPath = path.join(process.cwd(), 'src', 'js', 'capacitor-app.js');
|
|
215
|
-
|
|
216
|
-
if (fs.existsSync(appJsPath)) {
|
|
217
|
-
let appJsContent = fs.readFileSync(appJsPath, 'utf8');
|
|
218
|
-
|
|
219
|
-
const lines = appJsContent.split(/\r?\n/);
|
|
220
|
-
const newLines = [];
|
|
221
|
-
|
|
222
|
-
const targetKeywords = [
|
|
223
|
-
'Keyboard.setResizeMode',
|
|
224
|
-
'Keyboard.setScroll',
|
|
225
|
-
'Keyboard.setAccessoryBarVisible',
|
|
226
|
-
];
|
|
227
|
-
|
|
228
|
-
let insideIosWrap = false;
|
|
229
|
-
|
|
230
|
-
lines.forEach((line, index) => {
|
|
231
|
-
const trimmed = line.trim();
|
|
232
|
-
|
|
233
|
-
// detect already inside ios check
|
|
234
|
-
if (/if\s*\(\s*Capacitor\.getPlatform\(\)\s*===\s*['"]ios['"]\s*\)/.test(trimmed)) {
|
|
235
|
-
insideIosWrap = true;
|
|
236
|
-
newLines.push(line);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// detect closing of a block
|
|
241
|
-
if (insideIosWrap && trimmed === '}') {
|
|
242
|
-
insideIosWrap = false;
|
|
243
|
-
newLines.push(line);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const isKeyboardSetCall = targetKeywords.some((kw) => trimmed.startsWith(kw));
|
|
248
|
-
|
|
249
|
-
if (isKeyboardSetCall) {
|
|
250
|
-
if (!insideIosWrap) {
|
|
251
|
-
const indentMatch = line.match(/^(\s*)/);
|
|
252
|
-
const indent = indentMatch ? indentMatch[1] : '';
|
|
253
|
-
newLines.push(`${indent}if (Capacitor.getPlatform() === 'ios') {`);
|
|
254
|
-
newLines.push(`${indent} ${trimmed}`);
|
|
255
|
-
newLines.push(`${indent}}`);
|
|
256
|
-
console.log(`✅ Wrapped line ${index + 1} with ios check`);
|
|
257
|
-
} else {
|
|
258
|
-
// already inside ios wrap, leave alone
|
|
259
|
-
newLines.push(line);
|
|
260
|
-
}
|
|
261
|
-
} else {
|
|
262
|
-
newLines.push(line);
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
fs.writeFileSync(appJsPath, newLines.join('\n'), 'utf8');
|
|
267
|
-
console.log(`✅ All Keyboard.set* lines wrapped safely with ios check`);
|
|
268
|
-
}
|
|
269
|
-
else
|
|
270
|
-
{
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const configPath = path.join(process.cwd(), 'capacitor.config.json');
|
|
274
|
-
|
|
275
|
-
const rawData = fs.readFileSync(configPath, 'utf8');
|
|
276
|
-
const config = JSON.parse(rawData);
|
|
277
|
-
|
|
278
|
-
const appUniqueId=config.android.APP_UNIQUE_ID
|
|
279
|
-
|
|
280
|
-
if(appUniqueId!=172)
|
|
281
|
-
console.error(`❌ src/js/capacitor-app.js not found at: ${appJsPath}`);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
addFavIconCode()
|
|
294
|
-
appJssmallModifications();
|
|
295
|
-
replaceKeyboardSet()
|
|
296
|
-
|
|
297
|
-
ensureTouchHighlightDisabled()
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const configPath = path.join(process.cwd(), 'capacitor.config.json');
|
|
304
|
-
if (!fs.existsSync(configPath)) {
|
|
305
|
-
console.error(`❌ capacitor.config.json not found at: ${configPath}`);
|
|
306
|
-
//return;
|
|
307
|
-
}
|
|
308
|
-
const rawData = fs.readFileSync(configPath, 'utf8');
|
|
309
|
-
const config = JSON.parse(rawData);
|
|
310
|
-
const targetAppId=config.appId
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
function isNotificationFeatureUsed() {
|
|
320
|
-
const jsDir = path.join(process.cwd(), 'src', 'js');
|
|
321
|
-
|
|
322
|
-
if (!fs.existsSync(jsDir)) return false;
|
|
323
|
-
|
|
324
|
-
const notificationFiles = fs.readdirSync(jsDir).filter(file =>
|
|
325
|
-
/^onesignal-.*\.js$/.test(file) || /^localNotification-.*\.js$/.test(file)
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
if (notificationFiles.length === 0) return false;
|
|
329
|
-
|
|
330
|
-
// collect all js files to scan imports
|
|
331
|
-
const allJsFiles = [];
|
|
332
|
-
|
|
333
|
-
const walk = (dir) => {
|
|
334
|
-
fs.readdirSync(dir).forEach(file => {
|
|
335
|
-
const fullPath = path.join(dir, file);
|
|
336
|
-
if (fs.statSync(fullPath).isDirectory()) {
|
|
337
|
-
walk(fullPath);
|
|
338
|
-
} else if (file.endsWith('.js')) {
|
|
339
|
-
allJsFiles.push(fullPath);
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
walk(path.join(process.cwd(), 'src'));
|
|
345
|
-
|
|
346
|
-
// check if notification file is imported anywhere
|
|
347
|
-
for (const notifFile of notificationFiles) {
|
|
348
|
-
const importRegex = new RegExp(notifFile.replace('.js', ''), 'g');
|
|
349
|
-
|
|
350
|
-
for (const file of allJsFiles) {
|
|
351
|
-
const content = fs.readFileSync(file, 'utf8');
|
|
352
|
-
if (importRegex.test(content)) {
|
|
353
|
-
console.log(`🔔 Notification feature detected via ${notifFile}`);
|
|
354
|
-
return true;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
return false;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function addPostNotificationPermissionIfNeeded() {
|
|
363
|
-
const permission =
|
|
364
|
-
'<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />';
|
|
365
|
-
|
|
366
|
-
if (!isNotificationFeatureUsed()) {
|
|
367
|
-
console.log('ℹ️ Notification feature not used. Skipping POST_NOTIFICATIONS permission.');
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
console.log('✅ Notification feature is used. Ensuring POST_NOTIFICATIONS permission...');
|
|
372
|
-
addAndroidPermissions([permission]);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
addPostNotificationPermissionIfNeeded();
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
//console.log("TARGET APP ID IS : "+ targetAppId)
|
|
382
|
-
|
|
383
|
-
let permissions;
|
|
384
|
-
if(targetAppId=='apk.bulk.app.uninstaller' || targetAppId=='apk.extractor.installer')
|
|
385
|
-
{
|
|
386
|
-
permissions=[
|
|
387
|
-
'<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>',
|
|
388
|
-
'<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>',
|
|
389
|
-
'<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>'
|
|
390
|
-
];
|
|
391
|
-
|
|
392
|
-
// EXAMPLE USAGE
|
|
393
|
-
addAndroidPermissions(permissions);
|
|
394
|
-
}
|
|
395
|
-
else if(targetAppId=="image.to.text.document")
|
|
396
|
-
{
|
|
397
|
-
permissions=[
|
|
398
|
-
'<uses-permission android:name="android.permission.CAMERA" />',
|
|
399
|
-
'<uses-feature android:name="android.hardware.camera" android:required="true" />',
|
|
400
|
-
];
|
|
401
|
-
}
|
|
402
|
-
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Adds user permissions to AndroidManifest.xml if not already present
|
|
7
|
+
* based on capacitor.config.json appId matching.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} targetAppId - appId you want to match
|
|
10
|
+
* @param {string[]} permissionsToAdd - permission tags to insert
|
|
11
|
+
*/
|
|
12
|
+
function addAndroidPermissions(permissionsToAdd) {
|
|
13
|
+
try {
|
|
14
|
+
|
|
15
|
+
if (!Array.isArray(permissionsToAdd) || permissionsToAdd.length === 0) {
|
|
16
|
+
console.log("ℹ️ No permissions to add");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// read capacitor.config.json
|
|
21
|
+
const configPath = path.join(process.cwd(), 'capacitor.config.json');
|
|
22
|
+
if (!fs.existsSync(configPath)) {
|
|
23
|
+
console.error(`❌ capacitor.config.json not found at: ${configPath}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const rawData = fs.readFileSync(configPath, 'utf8');
|
|
28
|
+
const config = JSON.parse(rawData);
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
const androidManifestPath = path.join(
|
|
33
|
+
process.cwd(),
|
|
34
|
+
'android',
|
|
35
|
+
'app',
|
|
36
|
+
'src',
|
|
37
|
+
'main',
|
|
38
|
+
'AndroidManifest.xml'
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(androidManifestPath)) {
|
|
42
|
+
console.error(`❌ AndroidManifest.xml not found at: ${androidManifestPath}`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let manifestContent = fs.readFileSync(androidManifestPath, 'utf8');
|
|
47
|
+
let updated = false;
|
|
48
|
+
|
|
49
|
+
permissionsToAdd.forEach(permission => {
|
|
50
|
+
if (!manifestContent.includes(permission)) {
|
|
51
|
+
console.log(`🔧 Adding permission: ${permission}`);
|
|
52
|
+
manifestContent = manifestContent.replace(
|
|
53
|
+
'</manifest>',
|
|
54
|
+
` ${permission}\n</manifest>`
|
|
55
|
+
);
|
|
56
|
+
updated = true;
|
|
57
|
+
} else {
|
|
58
|
+
console.log(`ℹ️ Permission already exists: ${permission}`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (updated) {
|
|
63
|
+
fs.writeFileSync(androidManifestPath, manifestContent, 'utf8');
|
|
64
|
+
console.log('✅ AndroidManifest.xml updated successfully.');
|
|
65
|
+
} else {
|
|
66
|
+
console.log('✅ All required permissions already present.');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(`❌ Error: ${error.message}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
const addFavIconCode=()=>{
|
|
77
|
+
const htmlFilePath = path.join(process.cwd(), 'src', 'index.html');
|
|
78
|
+
|
|
79
|
+
if (fs.existsSync(htmlFilePath)) {
|
|
80
|
+
let htmlContent = fs.readFileSync(htmlFilePath, 'utf8');
|
|
81
|
+
|
|
82
|
+
const faviconTag = '<link rel="icon" href="data:;base64,iVBORw0KGgo=">';
|
|
83
|
+
|
|
84
|
+
if (!htmlContent.includes(faviconTag)) {
|
|
85
|
+
const headOpenTag = '<head>';
|
|
86
|
+
const headIndex = htmlContent.indexOf(headOpenTag);
|
|
87
|
+
|
|
88
|
+
if (headIndex !== -1) {
|
|
89
|
+
const insertPos = headIndex + headOpenTag.length;
|
|
90
|
+
htmlContent =
|
|
91
|
+
htmlContent.slice(0, insertPos) +
|
|
92
|
+
`\n ${faviconTag}` +
|
|
93
|
+
htmlContent.slice(insertPos);
|
|
94
|
+
|
|
95
|
+
fs.writeFileSync(htmlFilePath, htmlContent, 'utf8');
|
|
96
|
+
console.log(`✅ Favicon link added successfully to index.html`);
|
|
97
|
+
} else {
|
|
98
|
+
console.error('❌ <head> tag not found in index.html');
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
console.log('ℹ️ Favicon link already exists in index.html');
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
console.error(`❌ index.html not found at: ${htmlFilePath}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
const appJssmallModifications=()=>{
|
|
110
|
+
|
|
111
|
+
const appJsPath = path.join(process.cwd(), 'src', 'js', 'app.js');
|
|
112
|
+
|
|
113
|
+
if (fs.existsSync(appJsPath)) {
|
|
114
|
+
let appJsContent = fs.readFileSync(appJsPath, 'utf8');
|
|
115
|
+
|
|
116
|
+
// 1. ensure iosOverlaysWebView is true
|
|
117
|
+
if (/iosOverlaysWebView\s*:\s*false/.test(appJsContent)) {
|
|
118
|
+
appJsContent = appJsContent.replace(/iosOverlaysWebView\s*:\s*false/, 'iosOverlaysWebView: true');
|
|
119
|
+
console.log('✅ iosOverlaysWebView changed to true');
|
|
120
|
+
} else if (!/iosOverlaysWebView\s*:/.test(appJsContent)) {
|
|
121
|
+
// add if missing
|
|
122
|
+
appJsContent = appJsContent.replace(
|
|
123
|
+
/statusbar\s*:\s*\{/,
|
|
124
|
+
`statusbar: {\n iosOverlaysWebView: true,`
|
|
125
|
+
);
|
|
126
|
+
console.log('✅ iosOverlaysWebView added');
|
|
127
|
+
} else {
|
|
128
|
+
console.log('ℹ️ iosOverlaysWebView already true');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 2. ensure androidOverlaysWebView is true
|
|
132
|
+
if (/androidOverlaysWebView\s*:\s*false/.test(appJsContent)) {
|
|
133
|
+
appJsContent = appJsContent.replace(/androidOverlaysWebView\s*:\s*false/, 'androidOverlaysWebView: true');
|
|
134
|
+
console.log('✅ androidOverlaysWebView changed to true');
|
|
135
|
+
} else if (!/androidOverlaysWebView\s*:/.test(appJsContent)) {
|
|
136
|
+
// add if missing
|
|
137
|
+
appJsContent = appJsContent.replace(
|
|
138
|
+
/statusbar\s*:\s*\{/,
|
|
139
|
+
`statusbar: {\n androidOverlaysWebView: true,`
|
|
140
|
+
);
|
|
141
|
+
console.log('✅ androidOverlaysWebView added');
|
|
142
|
+
} else {
|
|
143
|
+
console.log('ℹ️ androidOverlaysWebView already true');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 3. change theme
|
|
147
|
+
const themeRegex = /theme\s*:\s*['"]auto['"]/;
|
|
148
|
+
if (themeRegex.test(appJsContent)) {
|
|
149
|
+
appJsContent = appJsContent.replace(themeRegex, `theme: 'md'`);
|
|
150
|
+
console.log('✅ theme changed to md');
|
|
151
|
+
} else {
|
|
152
|
+
console.log('ℹ️ theme: auto not found, no changes made');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
fs.writeFileSync(appJsPath, appJsContent, 'utf8');
|
|
156
|
+
console.log('✅ app.js updated successfully');
|
|
157
|
+
} else {
|
|
158
|
+
console.error(`❌ src/js/app.js not found at: ${appJsPath}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
const ensureTouchHighlightDisabled = () => {
|
|
164
|
+
const appJsPath = path.join(process.cwd(), 'src', 'js', 'app.js');
|
|
165
|
+
|
|
166
|
+
if (!fs.existsSync(appJsPath)) {
|
|
167
|
+
console.error(`❌ src/js/app.js not found at: ${appJsPath}`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let content = fs.readFileSync(appJsPath, 'utf8');
|
|
172
|
+
|
|
173
|
+
// 1️⃣ If explicitly true → change to false
|
|
174
|
+
if (/touchHighlightElements\s*:\s*true/.test(content)) {
|
|
175
|
+
content = content.replace(
|
|
176
|
+
/touchHighlightElements\s*:\s*true/g,
|
|
177
|
+
'touchHighlightElements: false'
|
|
178
|
+
);
|
|
179
|
+
console.log('✅ Updated touchHighlightElements true → false');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 2️⃣ If already false → skip
|
|
183
|
+
else if (/touchHighlightElements\s*:\s*false/.test(content)) {
|
|
184
|
+
console.log('ℹ️ touchHighlightElements already false');
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 3️⃣ If touch block exists → add inside it
|
|
189
|
+
else if (/touch\s*:\s*\{/.test(content)) {
|
|
190
|
+
content = content.replace(
|
|
191
|
+
/(touch\s*:\s*\{)/,
|
|
192
|
+
`$1\n touchHighlightElements: false,`
|
|
193
|
+
);
|
|
194
|
+
console.log('✅ Added touchHighlightElements inside existing touch block');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 4️⃣ If no touch block → create one
|
|
198
|
+
else {
|
|
199
|
+
content = content.replace(
|
|
200
|
+
/new Framework7\s*\(\s*\{/,
|
|
201
|
+
`new Framework7({\n touch: {\n touchHighlightElements: false\n },`
|
|
202
|
+
);
|
|
203
|
+
console.log('✅ Created new touch block with touchHighlightElements:false');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
fs.writeFileSync(appJsPath, content, 'utf8');
|
|
207
|
+
console.log('✅ Done updating app.js');
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
const replaceKeyboardSet=()=>{
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
const appJsPath = path.join(process.cwd(), 'src', 'js', 'capacitor-app.js');
|
|
215
|
+
|
|
216
|
+
if (fs.existsSync(appJsPath)) {
|
|
217
|
+
let appJsContent = fs.readFileSync(appJsPath, 'utf8');
|
|
218
|
+
|
|
219
|
+
const lines = appJsContent.split(/\r?\n/);
|
|
220
|
+
const newLines = [];
|
|
221
|
+
|
|
222
|
+
const targetKeywords = [
|
|
223
|
+
'Keyboard.setResizeMode',
|
|
224
|
+
'Keyboard.setScroll',
|
|
225
|
+
'Keyboard.setAccessoryBarVisible',
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
let insideIosWrap = false;
|
|
229
|
+
|
|
230
|
+
lines.forEach((line, index) => {
|
|
231
|
+
const trimmed = line.trim();
|
|
232
|
+
|
|
233
|
+
// detect already inside ios check
|
|
234
|
+
if (/if\s*\(\s*Capacitor\.getPlatform\(\)\s*===\s*['"]ios['"]\s*\)/.test(trimmed)) {
|
|
235
|
+
insideIosWrap = true;
|
|
236
|
+
newLines.push(line);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// detect closing of a block
|
|
241
|
+
if (insideIosWrap && trimmed === '}') {
|
|
242
|
+
insideIosWrap = false;
|
|
243
|
+
newLines.push(line);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const isKeyboardSetCall = targetKeywords.some((kw) => trimmed.startsWith(kw));
|
|
248
|
+
|
|
249
|
+
if (isKeyboardSetCall) {
|
|
250
|
+
if (!insideIosWrap) {
|
|
251
|
+
const indentMatch = line.match(/^(\s*)/);
|
|
252
|
+
const indent = indentMatch ? indentMatch[1] : '';
|
|
253
|
+
newLines.push(`${indent}if (Capacitor.getPlatform() === 'ios') {`);
|
|
254
|
+
newLines.push(`${indent} ${trimmed}`);
|
|
255
|
+
newLines.push(`${indent}}`);
|
|
256
|
+
console.log(`✅ Wrapped line ${index + 1} with ios check`);
|
|
257
|
+
} else {
|
|
258
|
+
// already inside ios wrap, leave alone
|
|
259
|
+
newLines.push(line);
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
newLines.push(line);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
fs.writeFileSync(appJsPath, newLines.join('\n'), 'utf8');
|
|
267
|
+
console.log(`✅ All Keyboard.set* lines wrapped safely with ios check`);
|
|
268
|
+
}
|
|
269
|
+
else
|
|
270
|
+
{
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
const configPath = path.join(process.cwd(), 'capacitor.config.json');
|
|
274
|
+
|
|
275
|
+
const rawData = fs.readFileSync(configPath, 'utf8');
|
|
276
|
+
const config = JSON.parse(rawData);
|
|
277
|
+
|
|
278
|
+
const appUniqueId=config.android.APP_UNIQUE_ID
|
|
279
|
+
|
|
280
|
+
if(appUniqueId!=172)
|
|
281
|
+
console.error(`❌ src/js/capacitor-app.js not found at: ${appJsPath}`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
addFavIconCode()
|
|
294
|
+
appJssmallModifications();
|
|
295
|
+
replaceKeyboardSet()
|
|
296
|
+
|
|
297
|
+
ensureTouchHighlightDisabled()
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
const configPath = path.join(process.cwd(), 'capacitor.config.json');
|
|
304
|
+
if (!fs.existsSync(configPath)) {
|
|
305
|
+
console.error(`❌ capacitor.config.json not found at: ${configPath}`);
|
|
306
|
+
//return;
|
|
307
|
+
}
|
|
308
|
+
const rawData = fs.readFileSync(configPath, 'utf8');
|
|
309
|
+
const config = JSON.parse(rawData);
|
|
310
|
+
const targetAppId=config.appId
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
function isNotificationFeatureUsed() {
|
|
320
|
+
const jsDir = path.join(process.cwd(), 'src', 'js');
|
|
321
|
+
|
|
322
|
+
if (!fs.existsSync(jsDir)) return false;
|
|
323
|
+
|
|
324
|
+
const notificationFiles = fs.readdirSync(jsDir).filter(file =>
|
|
325
|
+
/^onesignal-.*\.js$/.test(file) || /^localNotification-.*\.js$/.test(file)
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
if (notificationFiles.length === 0) return false;
|
|
329
|
+
|
|
330
|
+
// collect all js files to scan imports
|
|
331
|
+
const allJsFiles = [];
|
|
332
|
+
|
|
333
|
+
const walk = (dir) => {
|
|
334
|
+
fs.readdirSync(dir).forEach(file => {
|
|
335
|
+
const fullPath = path.join(dir, file);
|
|
336
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
337
|
+
walk(fullPath);
|
|
338
|
+
} else if (file.endsWith('.js')) {
|
|
339
|
+
allJsFiles.push(fullPath);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
walk(path.join(process.cwd(), 'src'));
|
|
345
|
+
|
|
346
|
+
// check if notification file is imported anywhere
|
|
347
|
+
for (const notifFile of notificationFiles) {
|
|
348
|
+
const importRegex = new RegExp(notifFile.replace('.js', ''), 'g');
|
|
349
|
+
|
|
350
|
+
for (const file of allJsFiles) {
|
|
351
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
352
|
+
if (importRegex.test(content)) {
|
|
353
|
+
console.log(`🔔 Notification feature detected via ${notifFile}`);
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function addPostNotificationPermissionIfNeeded() {
|
|
363
|
+
const permission =
|
|
364
|
+
'<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />';
|
|
365
|
+
|
|
366
|
+
if (!isNotificationFeatureUsed()) {
|
|
367
|
+
console.log('ℹ️ Notification feature not used. Skipping POST_NOTIFICATIONS permission.');
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
console.log('✅ Notification feature is used. Ensuring POST_NOTIFICATIONS permission...');
|
|
372
|
+
addAndroidPermissions([permission]);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
addPostNotificationPermissionIfNeeded();
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
//console.log("TARGET APP ID IS : "+ targetAppId)
|
|
382
|
+
|
|
383
|
+
let permissions;
|
|
384
|
+
if(targetAppId=='apk.bulk.app.uninstaller' || targetAppId=='apk.extractor.installer')
|
|
385
|
+
{
|
|
386
|
+
permissions=[
|
|
387
|
+
'<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>',
|
|
388
|
+
'<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>',
|
|
389
|
+
'<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>'
|
|
390
|
+
];
|
|
391
|
+
|
|
392
|
+
// EXAMPLE USAGE
|
|
393
|
+
addAndroidPermissions(permissions);
|
|
394
|
+
}
|
|
395
|
+
else if(targetAppId=="image.to.text.document")
|
|
396
|
+
{
|
|
397
|
+
permissions=[
|
|
398
|
+
'<uses-permission android:name="android.permission.CAMERA" />',
|
|
399
|
+
'<uses-feature android:name="android.hardware.camera" android:required="true" />',
|
|
400
|
+
];
|
|
401
|
+
}
|
|
402
|
+
|
|
403
403
|
addAndroidPermissions(permissions);
|