@gjsify/gi-runtime-android 0.0.0-stage → 0.61.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/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gjsify contributors
4
+
5
+ This license covers the SOURCE of this package (index.js, index.d.ts,
6
+ platforms/android/include.gradle) and the build script in the gjsify repository
7
+ that assembles the payload. It does NOT cover the third-party
8
+ GObject-Introspection binaries inside `platforms/android/gi-runtime-android.aar`:
9
+ those keep the terms of their own projects, named in
10
+ `platforms/THIRD-PARTY-NOTICES.md` inside the published tarball.
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,179 @@
1
- # Temporary Holding Version
1
+ # @gjsify/gi-runtime-android
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A **NativeScript plugin** that puts the GObject-Introspection runtime into an Android
4
+ APK: [`@gjsify/node-gi`](../node-gi)'s `libnode_gi.so`, the GLib / GObject / Gio
5
+ closure it links against, and their typelibs — for `arm64-v8a` and `x86_64`.
6
+
7
+ Add it as a dependency and `requireGi` works on the device. No `jniLibs` directory in
8
+ `App_Resources`, no hand-copied `.so`, no typelib path to configure.
9
+
10
+ ```jsonc
11
+ // package.json of a NativeScript app
12
+ "dependencies": {
13
+ "@gjsify/gi-runtime-android": "^0.60.0"
14
+ }
15
+ ```
16
+
17
+ > **NOT ON NPM YET.** The name has never been published, and npm's Trusted Publishing
18
+ > cannot create one — the first publish is a manual maintainer action, queued in
19
+ > [`status/pending-npm-bootstrap.json`](../../../status/pending-npm-bootstrap.json) with
20
+ > its command sequence. Until then the dependency above resolves to nothing; link the
21
+ > package locally (`file:` / `workspace:^`) to use it. Nothing in this repository pins
22
+ > the name, so the gap costs no other install.
23
+
24
+ Tier 3 (experimental). Stage 4 of
25
+ [ADR 0105](../../../docs/adr/0105-real-gobject-backs-the-nativescript-subset-on-android.md).
26
+
27
+ ## Why an AAR, and not `prebuilds/`
28
+
29
+ Nothing on Android resolves a `.node` file or a `node_modules` path at runtime. The
30
+ APK's `lib/<abi>/` is the only place `dlopen` looks without an absolute path, and only
31
+ the Android build system puts anything there. So the packaging envelope IS the delivery
32
+ mechanism: NativeScript's gradle scans every dependency's `platforms/android` for
33
+ `**/*.aar` and adds each hit as an `implementation` dependency, after which AGP merges
34
+ the AAR's `jni/<abi>/` into the APK's native libraries and its `assets/**` into the app
35
+ assets.
36
+
37
+ That is also why this is a package of its own rather than a directory inside
38
+ `@gjsify/node-gi`. npm has no per-platform file filtering: a `platforms/android/` inside
39
+ node-gi would make **every** transitive Node consumer a NativeScript plugin and put a
40
+ 33 MB AAR in every `npm install`. node-gi stays installable with zero Android bytes.
41
+
42
+ **One package, both ABIs** — not two per-ABI packages. A universal APK and gradle's
43
+ `abiFilters` both work from one AAR, and the app author adds one dependency.
44
+
45
+ **The addon travels WITH the GI stack.** `libnode_gi.so` names its GI libraries in
46
+ `DT_NEEDED`, so the loader resolves them before a line of JavaScript runs: an addon
47
+ built against one GLib and shipped beside another is a startup crash, not a version
48
+ warning. One artifact, one linked unit, one `sha256` per file in `gi-runtime.json`.
49
+
50
+ ## Layout
51
+
52
+ ```
53
+ platforms/
54
+ THIRD-PARTY-NOTICES.md generated; what the AAR carries, per project
55
+ android/
56
+ include.gradle COMMITTED — fails the app's build if the AAR is absent
57
+ gi-runtime-android.aar the payload (gitignored, built)
58
+ gi-runtime.json what went in: sizes, sha256, the closure, the typelib set
59
+ ```
60
+
61
+ Inside the AAR:
62
+
63
+ ```
64
+ AndroidManifest.xml package + minSdkVersion 24; nothing else
65
+ classes.jar empty — AGP expects the entry to exist
66
+ jni/<abi>/libnode_gi.so the node-gi addon
67
+ jni/<abi>/*.so the measured GI closure (14 libraries)
68
+ assets/app/girepository-1.0/*.typelib
69
+ ```
70
+
71
+ The typelib path is not a choice: NativeScript extracts the APK's `assets/app/**` to
72
+ `<filesDir>/app`, which makes that directory `<filesDir>/app/girepository-1.0` on the
73
+ device — exactly `host.nativescript.js`'s default for `__NODE_GI_TYPELIB_PATH`. The two
74
+ agree on purpose, so an app installing this plugin configures no paths.
75
+
76
+ ## The payload is built, never committed
77
+
78
+ Same arrangement as the `@gjsify/gtk-runtime-*` bundles' `gtk/`. A fresh checkout has no
79
+ AAR, which is what `include.gradle` is committed for: it turns the absence into a gradle
80
+ failure that names the build command, instead of an APK that dies in `dlopen` at startup.
81
+
82
+ ```sh
83
+ NDK=~/Android/Sdk/ndk/27.1.12297006
84
+ GI=~/.cache/gjsify-android/gi-probe/.pixiewood
85
+
86
+ # 1. the addon, per ABI — @gjsify/node-gi's own cross-build
87
+ for pair in arm64-v8a:aarch64 x86_64:x86_64; do
88
+ abi=${pair%%:*} arch=${pair##*:}
89
+ node ../node-gi/scripts/build-android.mjs --abi "$abi" --ndk "$NDK" \
90
+ --gi-sysroot "$GI/root" --out /tmp/gi-android/"$abi" \
91
+ --pkg-config-libdir "$GI/bin-$arch/meson-uninstalled" \
92
+ --napi-lib ~/.cache/gjsify-android/ns/aar
93
+ done
94
+
95
+ # 2. the bundle
96
+ node scripts/build-gi-runtime-android.mjs --ndk "$NDK" --gi-sysroot "$GI/root" \
97
+ --node-gi-lib /tmp/gi-android \
98
+ --typelib-dir "arm64-v8a=$GI/typelib-root/lib/arm64-v8a/girepository-1.0" \
99
+ --typelib-dir "x86_64=$GI/bin-x86_64/subprojects/glib/girepository/introspection"
100
+ ```
101
+
102
+ `--typelib-dir` is repeatable and per-ABI because a meson build tree has no single
103
+ typelib directory: one GI build keeps them in an install root, another one directory per
104
+ subproject. Omit it and the default is `<gi-sysroot>/lib/<abi>/girepository-1.0`.
105
+
106
+ ## What the build decides, and refuses
107
+
108
+ **The closure is measured, never listed.** The library set is the transitive `DT_NEEDED`
109
+ walk from `libnode_gi.so` through the GI prefix, so a dependency added upstream arrives
110
+ on its own and one dropped upstream leaves. A hand-written list drifts into either a
111
+ missing library (a crash on the device) or a dead one (megabytes in every APK), and both
112
+ are invisible in a checkout. Anything the walk cannot resolve inside the prefix must be
113
+ provided by **Android** or **NativeScript** — `SYSTEM_PROVIDED` says which, by name, and
114
+ a fourth answer fails the build.
115
+
116
+ Measured against the prefix above: **14 bundled** libraries, **7 system-provided**
117
+ (`libc`, `libm`, `libdl`, `liblog`, `libandroid`, `libz`, `libNativeScript`).
118
+
119
+ **The typelib set follows the closure.** The prefix offers 21 typelibs; the libraries
120
+ behind 14 of them are not in the closure (GTK, Pango, HarfBuzz, graphene, libadwaita),
121
+ so they are dropped. Shipping `Gtk-4.0.typelib` anyway would let `requireGi('Gtk')` find
122
+ a typelib, resolve against a `libgtk-4.so` that is not in the APK, and die in
123
+ `g_module_open` — a runtime failure that looks like a node-gi bug and is really a build
124
+ that copied a directory. The gate is `planTypelibSet` from
125
+ [`../scripts/typelib-backers.mjs`](../scripts/typelib-backers.mjs), the same one the
126
+ darwin and win32 bundles use; its `blocked` case fails the build when an unbacked typelib
127
+ *cannot* be dropped because a shipped namespace depends on it. **7 typelibs ship**: GLib,
128
+ GObject, Gio, GioUnix, GLibUnix, GModule, GIRepository.
129
+
130
+ **The typelibs are checked for ABI-neutrality.** An AAR has one `assets/` tree and no
131
+ per-ABI variant of it, so they come from one declared source ABI and are used by all of
132
+ them — sound only while they are neutral, and `.typelib` blobs are not neutral in
133
+ general, because they record struct sizes and field offsets. Every typelib is therefore
134
+ compared across every requested ABI, and an **undeclared** divergence fails the build.
135
+ Measured here: 6 of the 7 are byte-identical across `arm64-v8a` and `x86_64`; the
136
+ seventh and its consequence are recorded in
137
+ [`typelib-abi-divergence.json`](./typelib-abi-divergence.json).
138
+
139
+ **Every bundled library is attributed.** [`licenses/bundled-projects.json`](./licenses/bundled-projects.json)
140
+ maps soname → project; a soname the closure grew with no entry fails the notice
141
+ generation rather than shipping unattributed. The table is a NAME MAP and states no
142
+ terms: the Android GI prefix is a meson build tree and ships no licence corpus at all
143
+ (measured: zero `COPYING`/`LICENSE` files under the whole prefix), unlike the Homebrew
144
+ kegs the darwin bundle reads terms from. So the notice names each project and its
145
+ upstream and says plainly that the text is not embedded — an unspecific true claim
146
+ instead of an SPDX expression written from recollection, which is what `bundled-license`
147
+ refuses on win32 for the same reason. `--license-corpus <dir>` embeds texts when a build
148
+ has them.
149
+
150
+ ## Size
151
+
152
+ | | `arm64-v8a` | `x86_64` |
153
+ |---|---|---|
154
+ | stripped native libraries | 15.5 MB | 16.7 MB |
155
+
156
+ `llvm-strip --strip-unneeded` — not `--strip-all`, which on a shared library removes the
157
+ dynamic symbols the loader resolves through. The AAR stores uncompressed (33 MB for both
158
+ ABIs); AGP recompresses into the APK, so the AAR's own size is not the APK's. An
159
+ `abiFilters` build carries one column.
160
+
161
+ About **8 MB of each column is cairo's** — `libcairo`, `libcairo-gobject`, `libpixman-1`,
162
+ `libfreetype`, `libfontconfig`, `libpng16`, `libxml2`, pulled in because `libnode_gi.so`
163
+ links cairo for its canvas support. An app using only GObject and Gio pays for it. A
164
+ node-gi build without cairo would halve the payload and is not in scope here.
165
+
166
+ ## API
167
+
168
+ The payload is consumed by **gradle**, not by JavaScript — nothing has to import this
169
+ package for the plugin to work. `index.js` is the host-side view for a build script, a
170
+ device harness or a report that wants to know whether the payload is present and what is
171
+ in it:
172
+
173
+ ```js
174
+ import { isPresent, aarPath, deviceTypelibSubdir, readRuntimeManifest } from '@gjsify/gi-runtime-android';
175
+ ```
176
+
177
+ `readRuntimeManifest()` returns `gi-runtime.json` — the ABIs, the GI prefix the payload
178
+ was built from, every library and typelib with its size and `sha256`, and the AAR's own
179
+ digest — or `null` when the payload was never built.
package/index.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ /** One file inside the payload, as the build recorded it. */
4
+ export interface RuntimeEntry {
5
+ name: string;
6
+ bytes: number;
7
+ sha256: string;
8
+ }
9
+
10
+ /** The build's own record of the payload (`platforms/android/gi-runtime.json`). */
11
+ export interface RuntimeManifest {
12
+ builtAt: string;
13
+ abis: string[];
14
+ giSysroot: string;
15
+ /** ABI → the native libraries packaged for it, `libnode_gi.so` included. */
16
+ libraries: Record<string, RuntimeEntry[]>;
17
+ typelibs: RuntimeEntry[];
18
+ aar: { bytes: number; sha256: string };
19
+ }
20
+
21
+ /** The NativeScript plugin directory — what the NS gradle scans for `**\/*.aar`. */
22
+ export const platformsDir: string;
23
+ /** The AAR carrying both ABIs' native libraries and the shared typelibs. */
24
+ export const aarPath: string;
25
+ /** Sidecar written beside the AAR by the build: what went in, with sizes and digests. */
26
+ export const manifestPath: string;
27
+ /** Where the typelibs sit inside the AAR (`assets/app/girepository-1.0`). */
28
+ export const typelibAssetDir: string;
29
+ /** The device path the above lands at, relative to the app's files dir. */
30
+ export const deviceTypelibSubdir: string;
31
+ /** Whether the payload is actually on disk (it is built, never committed). */
32
+ export const isPresent: boolean;
33
+ /** The build's own record of the payload, or `null` when it was never built. */
34
+ export function readRuntimeManifest(): RuntimeManifest | null;
35
+
36
+ declare const _default: {
37
+ platformsDir: string;
38
+ aarPath: string;
39
+ manifestPath: string;
40
+ typelibAssetDir: string;
41
+ deviceTypelibSubdir: string;
42
+ isPresent: boolean;
43
+ readRuntimeManifest: typeof readRuntimeManifest;
44
+ };
45
+ export default _default;
package/index.js ADDED
@@ -0,0 +1,75 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // @gjsify/gi-runtime-android — host-side view of the NativeScript plugin payload.
3
+ //
4
+ // The payload is consumed by GRADLE, not by this file: NativeScript's build scans every
5
+ // dependency's `platforms/android` for `**/*.aar` and adds each as an `implementation`
6
+ // dependency, after which AGP packages `jni/<abi>/*.so` into the APK and merges
7
+ // `assets/**` into it. Nothing has to import this module for the plugin to work.
8
+ //
9
+ // What DOES have to be there is the `nativescript` key in package.json: the CLI lists only
10
+ // dependencies carrying one in `platforms/android/dependencies.json`, and that file is what
11
+ // gradle scans. Without the key the package installs, resolves and imports perfectly well
12
+ // and the APK gets nothing — a failure that looks like a node-gi bug on the device.
13
+ //
14
+ // What it is for is the HOST side of that: a build script, a device harness or a report
15
+ // that wants to know whether the payload is present and what is in it — before spending
16
+ // a gradle run to find out. The payload is built by scripts/build-gi-runtime-android.mjs
17
+ // and is gitignored, so `isPresent` is false in a fresh checkout.
18
+ import { existsSync, readFileSync } from 'node:fs';
19
+ import { dirname, join } from 'node:path';
20
+ import { fileURLToPath } from 'node:url';
21
+
22
+ const here = dirname(fileURLToPath(import.meta.url));
23
+
24
+ /** The NativeScript plugin directory — what the NS gradle scans for `**\/*.aar`. */
25
+ export const platformsDir = join(here, 'platforms', 'android');
26
+
27
+ /** The AAR carrying both ABIs' native libraries and the shared typelibs. */
28
+ export const aarPath = join(platformsDir, 'gi-runtime-android.aar');
29
+
30
+ /** Sidecar written beside the AAR by the build: what went in, with sizes and digests. */
31
+ export const manifestPath = join(platformsDir, 'gi-runtime.json');
32
+
33
+ /**
34
+ * Where the typelibs sit INSIDE the AAR, and where NativeScript therefore extracts them
35
+ * on the device: it copies the APK's `assets/app/**` to `<filesDir>/app`, which makes
36
+ * {@link deviceTypelibSubdir} the device path. That is `host.nativescript.js`'s default
37
+ * for `__NODE_GI_TYPELIB_PATH` — the two agree on purpose, so an app that installs this
38
+ * plugin needs no typelib configuration at all, and
39
+ * `packages/node-gi/node-gi/test/gi-runtime-android.test.mjs` holds the agreement — both
40
+ * directions, so moving either string alone fails a test instead of a device run.
41
+ */
42
+ export const typelibAssetDir = 'assets/app/girepository-1.0';
43
+
44
+ /** The device path the above lands at, relative to the app's files dir. */
45
+ export const deviceTypelibSubdir = 'app/girepository-1.0';
46
+
47
+ /** Whether the payload is actually on disk (it is built, never committed). */
48
+ export const isPresent = existsSync(aarPath);
49
+
50
+ /**
51
+ * The build's own record of the payload, or `null` when it was never built.
52
+ *
53
+ * @returns {{
54
+ * builtAt: string,
55
+ * abis: string[],
56
+ * giSysroot: string,
57
+ * libraries: Record<string, { name: string, bytes: number, sha256: string }[]>,
58
+ * typelibs: { name: string, bytes: number, sha256: string }[],
59
+ * aar: { bytes: number, sha256: string },
60
+ * } | null}
61
+ */
62
+ export function readRuntimeManifest() {
63
+ if (!existsSync(manifestPath)) return null;
64
+ return JSON.parse(readFileSync(manifestPath, 'utf8'));
65
+ }
66
+
67
+ export default {
68
+ platformsDir,
69
+ aarPath,
70
+ manifestPath,
71
+ typelibAssetDir,
72
+ deviceTypelibSubdir,
73
+ isPresent,
74
+ readRuntimeManifest,
75
+ };
package/package.json CHANGED
@@ -1,6 +1,54 @@
1
1
  {
2
- "name": "@gjsify/gi-runtime-android",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@gjsify/gi-runtime-android",
3
+ "version": "0.61.0",
4
+ "description": "NativeScript plugin that puts the GObject-Introspection runtime into an Android APK — libnode_gi.so plus the GLib/GObject/Gio closure and their typelibs, for arm64-v8a and x86_64. Add it as a dependency and @gjsify/node-gi's `requireGi` works on the device; no hand-copied .so, no jniLibs dir in App_Resources.",
5
+ "type": "module",
6
+ "license": "SEE LICENSE IN platforms/THIRD-PARTY-NOTICES.md",
7
+ "main": "./index.js",
8
+ "types": "./index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./index.d.ts",
12
+ "default": "./index.js"
13
+ },
14
+ "./platforms/android": "./platforms/android",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "index.js",
19
+ "index.d.ts",
20
+ "platforms"
21
+ ],
22
+ "nativescript": {
23
+ "platforms": {
24
+ "android": "7.0.0"
25
+ }
26
+ },
27
+ "gjsify": {
28
+ "runtimes": {
29
+ "gjs": "none",
30
+ "node": "none",
31
+ "browser": "none",
32
+ "nativescript": "native"
33
+ },
34
+ "nativescriptPlatforms": [
35
+ "android"
36
+ ],
37
+ "tier": 3
38
+ },
39
+ "scripts": {
40
+ "build:bundle": "node scripts/build-gi-runtime-android.mjs"
41
+ },
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/gjsify/gjsify.git",
45
+ "directory": "packages/node-gi/gi-runtime-android"
46
+ },
47
+ "keywords": [
48
+ "nativescript",
49
+ "android",
50
+ "gobject-introspection",
51
+ "glib",
52
+ "gjsify"
53
+ ]
54
+ }
@@ -0,0 +1,136 @@
1
+ # Third-party notices — @gjsify/gi-runtime-android
2
+
3
+ This package is an Android NativeScript plugin whose payload is an AAR of native
4
+ libraries. The three source files in it are MIT (see `LICENSE`); the AAR is not.
5
+
6
+ It carries, for arm64-v8a and x86_64:
7
+
8
+ - `libnode_gi.so` — @gjsify/node-gi's own addon, MIT, cross-compiled from this
9
+ repository against the GObject-Introspection stack below.
10
+ - 14 unmodified shared libraries from that stack, listed per project below.
11
+ - Their `.typelib` introspection data, generated by GLib's `g-ir-compiler` from the
12
+ same sources as the libraries it describes.
13
+
14
+ The libraries are UNMODIFIED except that `llvm-strip --strip-unneeded` removes the
15
+ symbols nothing in the APK resolves. No install name, rpath or soname is rewritten —
16
+ unlike the darwin bundle, Android needs none, because the APK's `lib/<abi>/` is the
17
+ loader's own search path.
18
+
19
+ ## What is NOT bundled
20
+
21
+ The closure also resolves against libraries already present in the process, which this
22
+ package therefore does not redistribute:
23
+
24
+ - `libNativeScript.so` — the NativeScript runtime AAR, already in the APK
25
+ - `libandroid.so` — Android platform (NDK stable ABI)
26
+ - `libc.so` — Bionic (platform)
27
+ - `libdl.so` — Bionic (platform)
28
+ - `liblog.so` — Android platform (NDK stable ABI)
29
+ - `libm.so` — Bionic (platform)
30
+ - `libz.so` — Android platform (NDK stable ABI)
31
+
32
+ ## Bundled projects
33
+
34
+ THE LICENCE TEXTS ARE NOT EMBEDDED, and this says so rather than guessing. The
35
+ Android GI prefix this bundles from is a meson build tree, which ships no licence
36
+ corpus — so unlike the darwin bundle, where every dylib resolves into a Homebrew keg
37
+ whose formula states the terms, there is nothing here to read them off. An SPDX
38
+ expression written from recollection would be a specific false claim in place of an
39
+ unspecific true one. Each project is named with its upstream, where the terms that
40
+ apply to the exact revision bundled are authoritative; pass `--license-corpus <dir>`
41
+ to a build to embed texts instead.
42
+
43
+ ### cairo
44
+
45
+ Upstream: https://gitlab.freedesktop.org/cairo/cairo
46
+
47
+ Bundled as:
48
+
49
+ - `libcairo-gobject.so`
50
+ - `libcairo.so`
51
+
52
+ Licence text: not embedded (see above). Upstream states the terms in `COPYING`, `COPYING-LGPL-2.1`, `COPYING-MPL-1.1`.
53
+
54
+ ### fontconfig
55
+
56
+ Upstream: https://gitlab.freedesktop.org/fontconfig/fontconfig
57
+
58
+ Bundled as:
59
+
60
+ - `libfontconfig.so`
61
+
62
+ Licence text: not embedded (see above). Upstream states the terms in `COPYING`.
63
+
64
+ ### FreeType
65
+
66
+ Upstream: https://gitlab.freedesktop.org/freetype/freetype
67
+
68
+ Bundled as:
69
+
70
+ - `libfreetype.so`
71
+
72
+ Licence text: not embedded (see above). Upstream states the terms in `LICENSE.TXT`, `docs/FTL.TXT`, `docs/GPLv2.TXT`.
73
+
74
+ ### GLib (GLib, GObject, GIO, GModule, GIRepository)
75
+
76
+ Upstream: https://gitlab.gnome.org/GNOME/glib
77
+
78
+ Bundled as:
79
+
80
+ - `libgio-2.0.so`
81
+ - `libgirepository-2.0.so`
82
+ - `libglib-2.0.so`
83
+ - `libgmodule-2.0.so`
84
+ - `libgobject-2.0.so`
85
+
86
+ Licence text: not embedded (see above). Upstream states the terms in `COPYING`.
87
+
88
+ ### libffi
89
+
90
+ Upstream: https://github.com/libffi/libffi
91
+
92
+ Bundled as:
93
+
94
+ - `libffi.so`
95
+
96
+ Licence text: not embedded (see above). Upstream states the terms in `LICENSE`.
97
+
98
+ ### libpng
99
+
100
+ Upstream: https://github.com/pnggroup/libpng
101
+
102
+ Bundled as:
103
+
104
+ - `libpng16.so`
105
+
106
+ Licence text: not embedded (see above). Upstream states the terms in `LICENSE`.
107
+
108
+ ### libxml2
109
+
110
+ Upstream: https://gitlab.gnome.org/GNOME/libxml2
111
+
112
+ Bundled as:
113
+
114
+ - `libxml2.so`
115
+
116
+ Licence text: not embedded (see above). Upstream states the terms in `Copyright`.
117
+
118
+ ### pixman
119
+
120
+ Upstream: https://gitlab.freedesktop.org/pixman/pixman
121
+
122
+ Bundled as:
123
+
124
+ - `libpixman-1.so`
125
+
126
+ Licence text: not embedded (see above). Upstream states the terms in `COPYING`.
127
+
128
+ ### proxy-libintl
129
+
130
+ Upstream: https://github.com/frida/proxy-libintl
131
+
132
+ Bundled as:
133
+
134
+ - `libintl.so`
135
+
136
+ Licence text: not embedded (see above). Upstream states the terms in `COPYING`.
@@ -0,0 +1,239 @@
1
+ {
2
+ "builtAt": "2026-10-12T13:11:08.415Z",
3
+ "abis": [
4
+ "arm64-v8a",
5
+ "x86_64"
6
+ ],
7
+ "giSysroot": "/home/jumplink/.cache/gjsify-android/gi-probe/.pixiewood/root",
8
+ "libraries": {
9
+ "arm64-v8a": [
10
+ {
11
+ "name": "libnode_gi.so",
12
+ "bytes": 866432,
13
+ "sha256": "e8b4c42113b715e5c7f30d84bae53af58593a86278e9e3c8fe2496d953d9a343"
14
+ },
15
+ {
16
+ "name": "libcairo-gobject.so",
17
+ "bytes": 36536,
18
+ "sha256": "a22eb00ff9145a43e2153f6a23eae70b1ef017c5018b3bf6c72a6de62a9f4587"
19
+ },
20
+ {
21
+ "name": "libcairo.so",
22
+ "bytes": 1550352,
23
+ "sha256": "61de994830b63d367906fcfde032b86edf937052dcbe6f6a2ef4f0edd2d70adf"
24
+ },
25
+ {
26
+ "name": "libffi.so",
27
+ "bytes": 50696,
28
+ "sha256": "7bcaaf2d4883268b4730ae57ba8dce78efa9fdc90491219cf5f7e683f2a3154d"
29
+ },
30
+ {
31
+ "name": "libfontconfig.so",
32
+ "bytes": 567352,
33
+ "sha256": "f55a2c54ef4233002e6d0382c4eaa5e8e0dd76b04115a303f2038261fc5c3ff9"
34
+ },
35
+ {
36
+ "name": "libfreetype.so",
37
+ "bytes": 1089552,
38
+ "sha256": "ba10557a5ab84bb888cb94fc049baf8f5fb0c108c3fcde2c36b7740c4ceaa40f"
39
+ },
40
+ {
41
+ "name": "libgio-2.0.so",
42
+ "bytes": 2707168,
43
+ "sha256": "1e8312859fbdfb74f00f3f2ecefcb8f4f07f341931be4168bd951702ad9292c7"
44
+ },
45
+ {
46
+ "name": "libgirepository-2.0.so",
47
+ "bytes": 339424,
48
+ "sha256": "be8aa142b52f8b8f3cf36f178d2c26ab4d0f0426a46da25624001167ec56bdf9"
49
+ },
50
+ {
51
+ "name": "libglib-2.0.so",
52
+ "bytes": 2629672,
53
+ "sha256": "551035e1dfacda670b308fbf62d3bccf4b3a77e228206e6b420f7b02e62def82"
54
+ },
55
+ {
56
+ "name": "libgmodule-2.0.so",
57
+ "bytes": 16416,
58
+ "sha256": "a3fa0548d39e0067f3ea6bffc57177be22940a58962e287ba705aab78bd3b2be"
59
+ },
60
+ {
61
+ "name": "libgobject-2.0.so",
62
+ "bytes": 499032,
63
+ "sha256": "3d3d577ff57f6dba29b969059f1a559c0d55491a00208246ec429af41c7d650a"
64
+ },
65
+ {
66
+ "name": "libintl.so",
67
+ "bytes": 6992,
68
+ "sha256": "6db136a9087804f21f4cd1e6eb8fb36252083d81e2d333b720d0e54719e4e238"
69
+ },
70
+ {
71
+ "name": "libpixman-1.so",
72
+ "bytes": 2895216,
73
+ "sha256": "055bf7ef3b8eb7e44d812fbc4456ef43b6126675bb92ee6ebc63ad19388814f2"
74
+ },
75
+ {
76
+ "name": "libpng16.so",
77
+ "bytes": 310888,
78
+ "sha256": "e1fe04b4a28850c1d5d35ffc6420fcb0b8b6ec7aaf5a407316767e17cdd04a5a"
79
+ },
80
+ {
81
+ "name": "libxml2.so",
82
+ "bytes": 1975400,
83
+ "sha256": "5125c88d1b0477edf3e55893e2fd9b5aeb2bc38d13ea318070978ec3c6cfb1bc"
84
+ }
85
+ ],
86
+ "x86_64": [
87
+ {
88
+ "name": "libnode_gi.so",
89
+ "bytes": 871816,
90
+ "sha256": "99a1e0814e5088eb17b022266403d519cf83be6048aa82c1add1f9d590fa18b2"
91
+ },
92
+ {
93
+ "name": "libcairo-gobject.so",
94
+ "bytes": 35496,
95
+ "sha256": "aa87ecbf34ce9d4c16538a5263867fd6281af5cfb1aa44040e62d85498b057f2"
96
+ },
97
+ {
98
+ "name": "libcairo.so",
99
+ "bytes": 1514968,
100
+ "sha256": "d9eed86aaeef1f90e86c05f6af3e3fdad331fd97fd729372a2b5351caec3e252"
101
+ },
102
+ {
103
+ "name": "libffi.so",
104
+ "bytes": 53408,
105
+ "sha256": "c4ecd9d7440a46eec33f3aae6d81e02c60f84570029246ddc3fc265e990f9bb3"
106
+ },
107
+ {
108
+ "name": "libfontconfig.so",
109
+ "bytes": 553016,
110
+ "sha256": "948f895e082bfb0788b0a7f31361fff676523e45698bcd63f7ef958cd66604f5"
111
+ },
112
+ {
113
+ "name": "libfreetype.so",
114
+ "bytes": 1061368,
115
+ "sha256": "d88956835cca79ca9e1b9d9f42b3edf29acf0a6d4ff22594f911abc5584fa41d"
116
+ },
117
+ {
118
+ "name": "libgio-2.0.so",
119
+ "bytes": 2630352,
120
+ "sha256": "c8fa7e7b178dc4535ccfb6c986f6cdee0febaf53197ad6403eba1fdf60abe5d3"
121
+ },
122
+ {
123
+ "name": "libgirepository-2.0.so",
124
+ "bytes": 320472,
125
+ "sha256": "fc3e4883c5ad2b3548348dcbe108595f678b3d252d9cc6904daeeac1d8ba1c26"
126
+ },
127
+ {
128
+ "name": "libglib-2.0.so",
129
+ "bytes": 2603744,
130
+ "sha256": "23272d2ef0eceb71f24b936258a7d691ca7dc454cc6b73d3c376a24dfde7f4a5"
131
+ },
132
+ {
133
+ "name": "libgmodule-2.0.so",
134
+ "bytes": 16912,
135
+ "sha256": "230740d7cffac8377a1d644bbf44df59c3d01a2931e654620703aba36cef9d17"
136
+ },
137
+ {
138
+ "name": "libgobject-2.0.so",
139
+ "bytes": 480296,
140
+ "sha256": "d06ec2f4f4fadd7d07da337b3d186206b853b9faca23da64626d0c058928cad5"
141
+ },
142
+ {
143
+ "name": "libintl.so",
144
+ "bytes": 6896,
145
+ "sha256": "7586662c25bcefc01b8a7e5a2bfb25e8626001acfe8793fc44654d0ea55d9128"
146
+ },
147
+ {
148
+ "name": "libpixman-1.so",
149
+ "bytes": 4378640,
150
+ "sha256": "0fa569f6364b34c8213db1c65a2d8640e47d2b2fd0547510022732bdf65fc18a"
151
+ },
152
+ {
153
+ "name": "libpng16.so",
154
+ "bytes": 295168,
155
+ "sha256": "db580cb38c1e7a527c711699d5b2d40e6dcc9c339e6b03d9fd6b65bb1e29106c"
156
+ },
157
+ {
158
+ "name": "libxml2.so",
159
+ "bytes": 1879464,
160
+ "sha256": "4b26180386b662e30fba15b70e48b05cce9fa6c36c2723ff272a1999de45679c"
161
+ }
162
+ ]
163
+ },
164
+ "systemProvided": [
165
+ {
166
+ "soname": "libNativeScript.so",
167
+ "provider": "the NativeScript runtime AAR, already in the APK"
168
+ },
169
+ {
170
+ "soname": "libandroid.so",
171
+ "provider": "Android platform (NDK stable ABI)"
172
+ },
173
+ {
174
+ "soname": "libc.so",
175
+ "provider": "Bionic (platform)"
176
+ },
177
+ {
178
+ "soname": "libdl.so",
179
+ "provider": "Bionic (platform)"
180
+ },
181
+ {
182
+ "soname": "liblog.so",
183
+ "provider": "Android platform (NDK stable ABI)"
184
+ },
185
+ {
186
+ "soname": "libm.so",
187
+ "provider": "Bionic (platform)"
188
+ },
189
+ {
190
+ "soname": "libz.so",
191
+ "provider": "Android platform (NDK stable ABI)"
192
+ }
193
+ ],
194
+ "typelibSourceAbi": "arm64-v8a",
195
+ "typelibDivergence": [
196
+ "GLib-2.0.typelib"
197
+ ],
198
+ "typelibs": [
199
+ {
200
+ "name": "GIRepository-3.0.typelib",
201
+ "bytes": 24952,
202
+ "sha256": "8221a0cb0611213d48a885b55bd476dc0537aa8d822c6b7f89789ca9546e73f4"
203
+ },
204
+ {
205
+ "name": "GLib-2.0.typelib",
206
+ "bytes": 230588,
207
+ "sha256": "283e81569ada35d7e70f740accc539fd6122046bdca22d33ff8ef09440c65598"
208
+ },
209
+ {
210
+ "name": "GLibUnix-2.0.typelib",
211
+ "bytes": 2144,
212
+ "sha256": "ecdb8d3901d34bc20ed533f06e131f2d3e9e78bccad2551086c68bc3dba1c6ea"
213
+ },
214
+ {
215
+ "name": "GModule-2.0.typelib",
216
+ "bytes": 1908,
217
+ "sha256": "97b84c3f0b1de28f0491aa6cf4fc60770e3ee33da4e6b5f11cf9055b7069e579"
218
+ },
219
+ {
220
+ "name": "GObject-2.0.typelib",
221
+ "bytes": 66424,
222
+ "sha256": "b413b57796c2776a6c31368701a7f6876dd063816b15313894be3730bf91926b"
223
+ },
224
+ {
225
+ "name": "Gio-2.0.typelib",
226
+ "bytes": 362032,
227
+ "sha256": "93742ced6316e806e0aab78a5f04390d359dced28e568ff70a2b23dcc546049e"
228
+ },
229
+ {
230
+ "name": "GioUnix-2.0.typelib",
231
+ "bytes": 14164,
232
+ "sha256": "a72d8a51f5299734737f8f22dd4df3dae795715b58e0c1506b002a4340d97176"
233
+ }
234
+ ],
235
+ "aar": {
236
+ "bytes": 32950881,
237
+ "sha256": "ada5b59b0753caa0745dcb62915ae47708df6ee21eb31555d332c12be01ebda3"
238
+ }
239
+ }
@@ -0,0 +1,44 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Applied by NativeScript into the app's gradle build, from this directory — the same
3
+ // directory it scans for `**/*.aar` (see @nativescript/android's app/build.gradle, where
4
+ // `$rootDir/${dep.directory}/platforms/android` supplies both the AAR list and this file).
5
+ //
6
+ // THE ONLY THING THIS DOES IS FAIL LOUDLY. The AAR beside it is the payload, it is
7
+ // gitignored, and it is built by `scripts/build-gi-runtime-android.mjs` against an Android
8
+ // GObject-Introspection prefix. In a fresh checkout — a locally linked worktree, a CI job
9
+ // that did not run the bundle build — it is simply ABSENT, and NativeScript's `**/*.aar`
10
+ // scan then finds nothing and says nothing: the app builds, installs, starts, and dies in
11
+ // `dlopen` the first time anything calls `requireGi`, with a message about
12
+ // `libnode_gi.so` and no hint that a build step was skipped hours earlier.
13
+ //
14
+ // So the absence is turned into a gradle failure that names the command to run. This file
15
+ // is the one thing in `platforms/` that is COMMITTED, for exactly that reason — a guard
16
+ // that ships with the payload is a guard that is missing whenever it is needed.
17
+ //
18
+ // `buildscript.sourceFile` is this script's own path: `projectDir` here is the APP's, not
19
+ // the plugin's, and hardcoding a `node_modules` path would break under `file:` links,
20
+ // pnpm's store and a gjsify worktree alike.
21
+ def gjsifyGiRuntimeDir = buildscript.sourceFile.parentFile
22
+ def gjsifyGiRuntimeAar = new File(gjsifyGiRuntimeDir, 'gi-runtime-android.aar')
23
+
24
+ if (!gjsifyGiRuntimeAar.exists()) {
25
+ throw new GradleException("""
26
+ @gjsify/gi-runtime-android has no payload: ${gjsifyGiRuntimeAar} does not exist.
27
+
28
+ This package carries libnode_gi.so, the GObject-Introspection libraries it needs and their
29
+ typelibs as ONE AAR, and that AAR is built rather than committed. Without it the APK would
30
+ contain no GI runtime at all and the app would fail in dlopen at the first requireGi call,
31
+ so the build stops here instead.
32
+
33
+ Build it in the gjsify checkout:
34
+
35
+ node packages/node-gi/node-gi/scripts/build-android.mjs --abi arm64-v8a --out <libdir> \\
36
+ --ndk <ndk> --gi-sysroot <prefix> --napi-lib <nativescript-aar>
37
+ node packages/node-gi/gi-runtime-android/scripts/build-gi-runtime-android.mjs \\
38
+ --ndk <ndk> --gi-sysroot <prefix> --node-gi-lib <libdir>
39
+
40
+ Both scripts print their options with --help; packages/node-gi/gi-runtime-android/README.md
41
+ has a worked invocation. An installed npm tarball always carries the AAR — this failure can
42
+ only happen against a source checkout.
43
+ """)
44
+ }