andysu-react-native 0.0.0-stage → 0.1.98

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.
@@ -0,0 +1,24 @@
1
+ // React Native autolinks this module. Inside the AndySU repo it compiles against :api; in an app it
2
+ // uses the published API artifact (compileOnly: the host provides the one runtime copy).
3
+ apply plugin: "com.android.library"
4
+
5
+ def andysuVersion = project.findProperty("andysuVersion") ?: "0.1.98"
6
+
7
+ android {
8
+ namespace "com.andysu.reactnative"
9
+ compileSdk 36
10
+ defaultConfig { minSdk 21 }
11
+ compileOptions {
12
+ sourceCompatibility JavaVersion.VERSION_17
13
+ targetCompatibility JavaVersion.VERSION_17
14
+ }
15
+ }
16
+
17
+ dependencies {
18
+ compileOnly "com.facebook.react:react-android:0.88.1"
19
+ if (findProject(":api") != null) {
20
+ compileOnly project(":api")
21
+ } else {
22
+ compileOnly "io.github.dixonsolutions.andysu:api:${andysuVersion}"
23
+ }
24
+ }
@@ -0,0 +1,96 @@
1
+ package com.andysu.reactnative;
2
+
3
+ import com.andysu.api.Host;
4
+ import com.andysu.api.HostApi;
5
+ import com.facebook.react.bridge.Promise;
6
+ import com.facebook.react.bridge.ReactApplicationContext;
7
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
8
+ import com.facebook.react.bridge.ReactMethod;
9
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
10
+
11
+ import org.json.JSONObject;
12
+
13
+ /** NativeModules.AndySU: a thin bridge to the AndySU host (com.andysu.api.Host). */
14
+ public class AndySUModule extends ReactContextBaseJavaModule {
15
+ public AndySUModule(ReactApplicationContext ctx) {
16
+ super(ctx);
17
+ }
18
+
19
+ @Override
20
+ public String getName() {
21
+ return "AndySU";
22
+ }
23
+
24
+ @ReactMethod
25
+ public void info(Promise p) {
26
+ HostApi h = Host.current();
27
+ try {
28
+ JSONObject o = new JSONObject().put("present", h != null);
29
+ if (h != null) {
30
+ o.put("apiLevel", h.apiLevel()).put("version", h.version()).put("isFactory", h.isFactory())
31
+ .put("slotDir", h.slotDir().getPath());
32
+ }
33
+ p.resolve(o.toString());
34
+ } catch (Exception e) {
35
+ p.reject("andysu", e);
36
+ }
37
+ }
38
+
39
+ @ReactMethod
40
+ public void status(Promise p) {
41
+ HostApi h = Host.current();
42
+ p.resolve(h == null ? "{\"state\":\"idle\"}" : h.updates().status());
43
+ }
44
+
45
+ @ReactMethod
46
+ public void checkNow() {
47
+ HostApi h = Host.current();
48
+ if (h != null) h.updates().checkNow();
49
+ }
50
+
51
+ @ReactMethod
52
+ public void applyNow() {
53
+ HostApi h = Host.current();
54
+ if (h != null) h.updates().applyNow();
55
+ }
56
+
57
+ @ReactMethod
58
+ public void restartNow() {
59
+ HostApi h = Host.current();
60
+ if (h != null) h.updates().restartNow();
61
+ }
62
+
63
+ @ReactMethod
64
+ public void setApplyPolicy(String policy) {
65
+ HostApi h = Host.current();
66
+ if (h != null) h.updates().setApplyPolicy(policy);
67
+ }
68
+
69
+ @ReactMethod
70
+ public void applyPolicy(Promise p) {
71
+ HostApi h = Host.current();
72
+ p.resolve(h == null ? "live" : h.updates().applyPolicy());
73
+ }
74
+
75
+ @ReactMethod
76
+ public void markHealthy() {
77
+ HostApi h = Host.current();
78
+ if (h != null) h.markHealthy();
79
+ }
80
+
81
+ @ReactMethod
82
+ public void listen() {
83
+ HostApi h = Host.current();
84
+ if (h == null) return;
85
+ h.updates().setListener(json -> getReactApplicationContext()
86
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
87
+ .emit("AndySUStatus", json));
88
+ }
89
+
90
+ // Required by NativeEventEmitter on the JS side.
91
+ @ReactMethod
92
+ public void addListener(String eventName) {}
93
+
94
+ @ReactMethod
95
+ public void removeListeners(double count) {}
96
+ }
@@ -0,0 +1,21 @@
1
+ package com.andysu.reactnative;
2
+
3
+ import com.facebook.react.ReactPackage;
4
+ import com.facebook.react.bridge.NativeModule;
5
+ import com.facebook.react.bridge.ReactApplicationContext;
6
+ import com.facebook.react.uimanager.ViewManager;
7
+
8
+ import java.util.Collections;
9
+ import java.util.List;
10
+
11
+ public class AndySUPackage implements ReactPackage {
12
+ @Override
13
+ public List<NativeModule> createNativeModules(ReactApplicationContext ctx) {
14
+ return Collections.singletonList(new AndySUModule(ctx));
15
+ }
16
+
17
+ @Override
18
+ public List<ViewManager> createViewManagers(ReactApplicationContext ctx) {
19
+ return Collections.emptyList();
20
+ }
21
+ }
package/app.plugin.js ADDED
@@ -0,0 +1,13 @@
1
+ // Expo config plugin. AndySU needs nothing in the app's own manifest: the frozen host is produced
2
+ // from the finished APK by `andysu split --transparent` (or the Gradle plugin). The plugin records
3
+ // the andysu.toml location in the Android app's gradle.properties so build scripts can find it.
4
+ const { withGradleProperties } = require('@expo/config-plugins');
5
+
6
+ module.exports = function withAndySU(config, props = {}) {
7
+ return withGradleProperties(config, (c) => {
8
+ const key = 'andysu.toml';
9
+ c.modResults = c.modResults.filter((p) => !(p.type === 'property' && p.key === key));
10
+ c.modResults.push({ type: 'property', key, value: props.toml || '../andysu.toml' });
11
+ return c;
12
+ });
13
+ };
package/lib/index.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ /** Update status as reported by the AndySU host. */
2
+ export interface Status {
3
+ state: 'idle' | 'checking' | 'up_to_date' | 'deferred' | 'available' | 'downloading' | 'staged' | 'applying' | 'shell_update' | 'error';
4
+ release?: string;
5
+ hot_only?: boolean;
6
+ mandatory?: boolean;
7
+ download_bytes?: number;
8
+ code?: string;
9
+ message?: string;
10
+ [k: string]: unknown;
11
+ }
12
+ export interface HostInfo {
13
+ /** False when the app is not running under an AndySU host (e.g. a debug build). */
14
+ present: boolean;
15
+ apiLevel?: number;
16
+ version?: string;
17
+ isFactory?: boolean;
18
+ slotDir?: string;
19
+ }
20
+ /** Information about the running payload. */
21
+ export declare function info(): Promise<HostInfo>;
22
+ /** The updater's current status. */
23
+ export declare function status(): Promise<Status>;
24
+ /** Check now (download and stage according to the configured mode). */
25
+ export declare function checkNow(): void;
26
+ /** Apply a staged update now (live if possible, otherwise by restarting). */
27
+ export declare function applyNow(): void;
28
+ /** Restart into the newest staged or committed payload. */
29
+ export declare function restartNow(): void;
30
+ export type ApplyPolicy = 'live' | 'restart' | 'next_start';
31
+ /**
32
+ * How staged updates apply on this install: swap live (the default), restart the app, or wait for
33
+ * the next start. Pass null to return to the policy configured in andysu.toml.
34
+ */
35
+ export declare function setApplyPolicy(policy: ApplyPolicy | null): void;
36
+ export declare function applyPolicy(): Promise<ApplyPolicy>;
37
+ /** Commit this payload generation (call once the app is known to work). */
38
+ export declare function markHealthy(): void;
39
+ /** Listen for status changes. Returns an unsubscribe function. */
40
+ export declare function onStatus(cb: (s: Status) => void): () => void;
package/lib/index.js ADDED
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.info = info;
4
+ exports.status = status;
5
+ exports.checkNow = checkNow;
6
+ exports.applyNow = applyNow;
7
+ exports.restartNow = restartNow;
8
+ exports.setApplyPolicy = setApplyPolicy;
9
+ exports.applyPolicy = applyPolicy;
10
+ exports.markHealthy = markHealthy;
11
+ exports.onStatus = onStatus;
12
+ const react_native_1 = require("react-native");
13
+ const native = react_native_1.Platform.OS === 'android' ? react_native_1.NativeModules.AndySU : undefined;
14
+ /** Information about the running payload. */
15
+ async function info() {
16
+ if (!native)
17
+ return { present: false };
18
+ return JSON.parse(await native.info());
19
+ }
20
+ /** The updater's current status. */
21
+ async function status() {
22
+ if (!native)
23
+ return { state: 'idle' };
24
+ return JSON.parse(await native.status());
25
+ }
26
+ /** Check now (download and stage according to the configured mode). */
27
+ function checkNow() {
28
+ native === null || native === void 0 ? void 0 : native.checkNow();
29
+ }
30
+ /** Apply a staged update now (live if possible, otherwise by restarting). */
31
+ function applyNow() {
32
+ native === null || native === void 0 ? void 0 : native.applyNow();
33
+ }
34
+ /** Restart into the newest staged or committed payload. */
35
+ function restartNow() {
36
+ native === null || native === void 0 ? void 0 : native.restartNow();
37
+ }
38
+ /**
39
+ * How staged updates apply on this install: swap live (the default), restart the app, or wait for
40
+ * the next start. Pass null to return to the policy configured in andysu.toml.
41
+ */
42
+ function setApplyPolicy(policy) {
43
+ native === null || native === void 0 ? void 0 : native.setApplyPolicy(policy);
44
+ }
45
+ async function applyPolicy() {
46
+ if (!native)
47
+ return 'live';
48
+ return native.applyPolicy();
49
+ }
50
+ /** Commit this payload generation (call once the app is known to work). */
51
+ function markHealthy() {
52
+ native === null || native === void 0 ? void 0 : native.markHealthy();
53
+ }
54
+ /** Listen for status changes. Returns an unsubscribe function. */
55
+ function onStatus(cb) {
56
+ if (!native)
57
+ return () => { };
58
+ const sub = new react_native_1.NativeEventEmitter(native).addListener('AndySUStatus', (json) => cb(JSON.parse(json)));
59
+ native.listen();
60
+ return () => sub.remove();
61
+ }
package/package.json CHANGED
@@ -1,6 +1,31 @@
1
1
  {
2
2
  "name": "andysu-react-native",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.98",
4
+ "description": "AndySU self-updates for React Native and Expo apps on Android (status, check, apply)",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/dixonSolutions/AndySU",
9
+ "directory": "bindings/react-native"
10
+ },
11
+ "main": "lib/index.js",
12
+ "types": "lib/index.d.ts",
13
+ "files": [
14
+ "lib",
15
+ "src",
16
+ "android/build.gradle",
17
+ "android/src",
18
+ "app.plugin.js",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "test": "node test/smoke.js"
24
+ },
25
+ "peerDependencies": {
26
+ "react-native": ">=0.70"
27
+ },
28
+ "devDependencies": {
29
+ "typescript": "^5.6.0"
30
+ }
31
+ }
package/src/index.ts ADDED
@@ -0,0 +1,80 @@
1
+ import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
+
3
+ /** Update status as reported by the AndySU host. */
4
+ export interface Status {
5
+ state: 'idle' | 'checking' | 'up_to_date' | 'deferred' | 'available' | 'downloading' | 'staged' |
6
+ 'applying' | 'shell_update' | 'error';
7
+ release?: string;
8
+ hot_only?: boolean;
9
+ mandatory?: boolean;
10
+ download_bytes?: number;
11
+ code?: string;
12
+ message?: string;
13
+ [k: string]: unknown;
14
+ }
15
+
16
+ export interface HostInfo {
17
+ /** False when the app is not running under an AndySU host (e.g. a debug build). */
18
+ present: boolean;
19
+ apiLevel?: number;
20
+ version?: string;
21
+ isFactory?: boolean;
22
+ slotDir?: string;
23
+ }
24
+
25
+ const native = Platform.OS === 'android' ? NativeModules.AndySU : undefined;
26
+
27
+ /** Information about the running payload. */
28
+ export async function info(): Promise<HostInfo> {
29
+ if (!native) return { present: false };
30
+ return JSON.parse(await native.info());
31
+ }
32
+
33
+ /** The updater's current status. */
34
+ export async function status(): Promise<Status> {
35
+ if (!native) return { state: 'idle' };
36
+ return JSON.parse(await native.status());
37
+ }
38
+
39
+ /** Check now (download and stage according to the configured mode). */
40
+ export function checkNow(): void {
41
+ native?.checkNow();
42
+ }
43
+
44
+ /** Apply a staged update now (live if possible, otherwise by restarting). */
45
+ export function applyNow(): void {
46
+ native?.applyNow();
47
+ }
48
+
49
+ /** Restart into the newest staged or committed payload. */
50
+ export function restartNow(): void {
51
+ native?.restartNow();
52
+ }
53
+
54
+ export type ApplyPolicy = 'live' | 'restart' | 'next_start';
55
+
56
+ /**
57
+ * How staged updates apply on this install: swap live (the default), restart the app, or wait for
58
+ * the next start. Pass null to return to the policy configured in andysu.toml.
59
+ */
60
+ export function setApplyPolicy(policy: ApplyPolicy | null): void {
61
+ native?.setApplyPolicy(policy);
62
+ }
63
+
64
+ export async function applyPolicy(): Promise<ApplyPolicy> {
65
+ if (!native) return 'live';
66
+ return native.applyPolicy();
67
+ }
68
+
69
+ /** Commit this payload generation (call once the app is known to work). */
70
+ export function markHealthy(): void {
71
+ native?.markHealthy();
72
+ }
73
+
74
+ /** Listen for status changes. Returns an unsubscribe function. */
75
+ export function onStatus(cb: (s: Status) => void): () => void {
76
+ if (!native) return () => {};
77
+ const sub = new NativeEventEmitter(native).addListener('AndySUStatus', (json: string) => cb(JSON.parse(json)));
78
+ native.listen();
79
+ return () => sub.remove();
80
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
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.