Skip to content

Commit 8399589

Browse files
Alpine Linux Backend (#1401)
* feat. add all required native libs * feat. added helper functions * downgrade cordova version * feat. added support for x64 * first working implementation * add missing config * downgrade cordova version * fix. internet * improvements * fixed stuff * fix. filesDir not defined * feat. handle fdroid flavor * feat. handle fdroid flavor * fix. stopAxs not working * fix. foxed stopAxs() and isAxsRunning() * set home directory * feat: add "Terminal Home" in acode file browser Added " Terminal Home " in storage list in acode built in file browser for easy access of terminal files and workflow * use correct keyboard for process id * feat. added jsDoc for Terminal api --------- Co-authored-by: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com>
1 parent 1385715 commit 8399589

File tree

26 files changed

+728
-61
lines changed

26 files changed

+728
-61
lines changed

biome.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@
3434
"globals": ["Global1"]
3535
},
3636
"files": {
37-
"include": ["src/**/*", "utils/**/*.js", "www/**/*.js", "www/res/**/*.css"],
37+
"include": [
38+
"src/**/*",
39+
"utils/**/*.js",
40+
"www/**/*.js",
41+
"www/res/**/*.css",
42+
"src/plugins/terminal"
43+
],
3844
"ignore": [
3945
"ace-builds",
4046
"www/js/**/*.js",

hooks/post-process.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable no-console */
22
const path = require('path');
33
const fs = require('fs');
4+
const { execSync } = require('child_process');
45

56
const buildFilePath = path.resolve(__dirname, '../build.json');
67
const copyToPath = path.resolve(__dirname, '../platforms/android/build.json');
@@ -28,6 +29,35 @@ deleteDirRecursively(resPath, [
2829
'xml',
2930
]);
3031
copyDirRecursively(localResPath, resPath);
32+
enableLegacyJni()
33+
34+
35+
function enableLegacyJni() {
36+
const prefix = execSync('npm prefix').toString().trim();
37+
const gradleFile = path.join(prefix, 'platforms/android/app/build.gradle');
38+
39+
if (!fs.existsSync(gradleFile)) return;
40+
41+
let content = fs.readFileSync(gradleFile, 'utf-8');
42+
// Check for correct block to avoid duplicate insertion
43+
if (content.includes('useLegacyPackaging = true')) return;
44+
45+
// Inject under android block with correct Groovy syntax
46+
content = content.replace(/android\s*{/, match => {
47+
return (
48+
match +
49+
`
50+
packagingOptions {
51+
jniLibs {
52+
useLegacyPackaging = true
53+
}
54+
}`
55+
);
56+
});
57+
58+
fs.writeFileSync(gradleFile, content, 'utf-8');
59+
console.log('[Cordova Hook] ✅ Enabled legacy JNI packaging');
60+
}
3161

3262
/**
3363
* Copy directory recursively

package-lock.json

Lines changed: 26 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@
3131
"cordova-plugin-sdcard": {},
3232
"cordova-plugin-browser": {},
3333
"cordova-plugin-iap": {},
34-
"cordova-plugin-system": {},
3534
"cordova-plugin-advanced-http": {
3635
"ANDROIDBLACKLISTSECURESOCKETPROTOCOLS": "SSLv3,TLSv1"
3736
},
3837
"cordova-plugin-websocket": {},
39-
"com.foxdebug.acode.rk.exec.terminal": {},
40-
"cordova-plugin-buildinfo": {}
38+
"cordova-plugin-buildinfo": {},
39+
"cordova-plugin-system": {},
40+
"com.foxdebug.acode.rk.exec.terminal": {}
4141
},
4242
"platforms": [
4343
"android"
@@ -88,6 +88,7 @@
8888
"sass": "^1.77.2",
8989
"sass-loader": "^14.2.1",
9090
"style-loader": "^4.0.0",
91+
"terminal": "^0.1.4",
9192
"webpack": "^5.94.0",
9293
"webpack-cli": "^5.1.4"
9394
},

src/lib/checkFiles.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ export default async function checkFiles() {
4747
* @returns {Promise<void>}
4848
*/
4949
async function checkFile(file) {
50-
if (file.isUnsaved || !file.loaded || file.loading) return;
50+
if (file === undefined || file.isUnsaved || !file.loaded || file.loading)
51+
return;
5152

5253
if (file.uri) {
5354
const fs = fsOperation(file.uri);

src/lib/main.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ import NotificationManager from "lib/notificationManager";
5454
import { addedFolder } from "lib/openFolder";
5555
import { getEncoding, initEncodings } from "utils/encodings";
5656
import auth, { loginEvents } from "./auth";
57-
import constants from "./constants";
5857

5958
const previousVersionCode = Number.parseInt(localStorage.versionCode, 10);
6059

src/pages/fileBrowser/fileBrowser.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,33 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) {
10331033
);
10341034
}
10351035

1036+
// Check for Terminal Home Directory storage
1037+
try {
1038+
const isTerminalInstalled = await Terminal.isInstalled();
1039+
if (typeof Terminal !== "undefined" && isTerminalInstalled) {
1040+
const isTerminalSupported = await Terminal.isSupported();
1041+
1042+
if (isTerminalSupported && isTerminalInstalled) {
1043+
const terminalHomeUrl = cordova.file.dataDirectory + "alpine/home";
1044+
1045+
// Check if this storage is not already in the list
1046+
const terminalStorageExists = allStorages.find(
1047+
(storage) =>
1048+
storage.uuid === "terminal-home" ||
1049+
storage.url === terminalHomeUrl,
1050+
);
1051+
1052+
if (!terminalStorageExists) {
1053+
util.pushFolder(allStorages, "Terminal Home", terminalHomeUrl, {
1054+
uuid: "terminal-home",
1055+
});
1056+
}
1057+
}
1058+
}
1059+
} catch (error) {
1060+
console.error("Error checking Terminal installation:", error);
1061+
}
1062+
10361063
try {
10371064
const res = await externalFs.listStorages();
10381065
res.forEach((storage) => {

src/plugins/system/android/com/foxdebug/system/System.java

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.foxdebug.system;
22

3+
4+
import java.nio.file.Files;
5+
import java.nio.file.Paths;
6+
import java.nio.file.StandardOpenOption;
7+
import java.io.IOException;
38
import android.app.Activity;
49
import android.app.PendingIntent;
510
import android.content.ClipData;
@@ -47,6 +52,10 @@
4752
import org.json.JSONArray;
4853
import org.json.JSONException;
4954
import org.json.JSONObject;
55+
import java.nio.file.Files;
56+
import java.nio.file.LinkOption;
57+
import java.nio.file.Path;
58+
5059

5160
public class System extends CordovaPlugin {
5261

@@ -156,6 +165,66 @@ public void run() {
156165
}
157166
);
158167
return true;
168+
case "fileExists":
169+
callbackContext.success(fileExists(args.getString(0),args.getString(1)) ? 1 : 0);
170+
return true;
171+
172+
case "createSymlink":
173+
boolean success = createSymlink(args.getString(0), args.getString(1));
174+
callbackContext.success(success ? 1 : 0);
175+
return true;
176+
177+
case "getNativeLibraryPath":
178+
callbackContext.success(getNativeLibraryPath());
179+
return true;
180+
181+
case "getFilesDir":
182+
callbackContext.success(getFilesDir());
183+
return true;
184+
185+
case "getParentPath":
186+
callbackContext.success(getParentPath(args.getString(0)));
187+
return true;
188+
189+
case "listChildren":
190+
callbackContext.success(listChildren(args.getString(0)));
191+
return true;
192+
case "writeText": {
193+
try {
194+
String filePath = args.getString(0);
195+
String content = args.getString(1);
196+
197+
Files.write(Paths.get(filePath),
198+
Collections.singleton(content),
199+
StandardOpenOption.CREATE,
200+
StandardOpenOption.TRUNCATE_EXISTING);
201+
202+
callbackContext.success("File written successfully");
203+
} catch (Exception e) {
204+
callbackContext.error("Failed to write file: " + e.getMessage());
205+
}
206+
return true;
207+
}
208+
209+
case "getArch":
210+
String arch;
211+
212+
if (android.os.Build.VERSION.SDK_INT >= 21) {
213+
arch = android.os.Build.SUPPORTED_ABIS[0];
214+
} else {
215+
arch = android.os.Build.CPU_ABI;
216+
}
217+
218+
callbackContext.success(arch);
219+
return true;
220+
case "mkdirs":
221+
File file = new File(args.getString(0));
222+
if(file.mkdirs()){
223+
callbackContext.success();
224+
}else{
225+
callbackContext.error("mkdirs failed");
226+
}
227+
return true;
159228
default:
160229
return false;
161230
}
@@ -399,6 +468,59 @@ private void hasPermission(String permission, CallbackContext callback) {
399468
callback.error("No permission passed to check.");
400469
}
401470

471+
public boolean fileExists(String path, String countSymlinks) {
472+
Path p = new File(path).toPath();
473+
try {
474+
if (Boolean.parseBoolean(countSymlinks)) {
475+
// This will return true even for broken symlinks
476+
return Files.exists(p, LinkOption.NOFOLLOW_LINKS);
477+
} else {
478+
// Check target file, not symlink itself
479+
return Files.exists(p) && !Files.isSymbolicLink(p);
480+
}
481+
} catch (Exception e) {
482+
return false;
483+
}
484+
}
485+
486+
public boolean createSymlink(String target, String linkPath) {
487+
try {
488+
Process process = Runtime.getRuntime().exec(new String[]{"ln", "-s", target, linkPath});
489+
return process.waitFor() == 0;
490+
} catch (Exception e) {
491+
return false;
492+
}
493+
}
494+
495+
public String getNativeLibraryPath() {
496+
ApplicationInfo appInfo = context.getApplicationInfo();
497+
return appInfo.nativeLibraryDir;
498+
}
499+
500+
public String getFilesDir() {
501+
return context.getFilesDir().getAbsolutePath();
502+
}
503+
504+
public String getParentPath(String path) {
505+
File file = new File(path);
506+
File parent = file.getParentFile();
507+
return parent != null ? parent.getAbsolutePath() : null;
508+
}
509+
510+
public JSONArray listChildren(String path) throws JSONException {
511+
File dir = new File(path);
512+
JSONArray result = new JSONArray();
513+
if (dir.exists() && dir.isDirectory()) {
514+
File[] files = dir.listFiles();
515+
if (files != null) {
516+
for (File file : files) {
517+
result.put(file.getAbsolutePath());
518+
}
519+
}
520+
}
521+
return result;
522+
}
523+
402524
public void onRequestPermissionResult(
403525
int code,
404526
String[] permissions,

src/plugins/system/www/plugin.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,37 @@
11
module.exports = {
2+
fileExists: function (path,countSymlinks, success, error) {
3+
cordova.exec(success, error, 'System', 'fileExists', [path,String(countSymlinks)]);
4+
},
5+
6+
createSymlink: function (target, linkPath, success, error) {
7+
cordova.exec(success, error, 'System', 'createSymlink', [target, linkPath]);
8+
},
9+
writeText: function (path, content, success, error) {
10+
cordova.exec(success, error, 'System', 'writeText', [path, content]);
11+
},
12+
13+
getNativeLibraryPath: function (success, error) {
14+
cordova.exec(success, error, 'System', 'getNativeLibraryPath', []);
15+
},
16+
17+
getFilesDir: function (success, error) {
18+
cordova.exec(success, error, 'System', 'getFilesDir', []);
19+
},
20+
21+
getParentPath: function (path, success, error) {
22+
cordova.exec(success, error, 'System', 'getParentPath', [path]);
23+
},
24+
25+
listChildren: function (path, success, error) {
26+
cordova.exec(success, error, 'System', 'listChildren', [path]);
27+
},
28+
mkdirs: function (path, success, error) {
29+
cordova.exec(success, error, 'System', 'mkdirs', [path]);
30+
},
31+
getArch: function (success, error) {
32+
cordova.exec(success, error, 'System', 'getArch', []);
33+
},
34+
235
clearCache: function (success, fail) {
336
return cordova.exec(success, fail, "System", "clearCache", []);
437
},
175 KB
Binary file not shown.

0 commit comments

Comments
 (0)