Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3f18813
Add Capacitor Android target and platform abstraction
zortos293 Apr 10, 2026
ec1dd5f
Fix Android review issues
zortos293 Apr 10, 2026
7b88b70
Unify Android package naming
zortos293 Apr 10, 2026
698591d
Add Android APK CI build
zortos293 Apr 10, 2026
787f173
Remove Capacitor HTTP plugin dependency
zortos293 Apr 10, 2026
3eb35a2
Match Android auth callback to desktop
zortos293 Apr 10, 2026
5b26e58
Fix Android localhost auth plugin compile
zortos293 Apr 10, 2026
07b3379
Fix Android localhost OAuth callback flow
zortos293 Apr 10, 2026
c24021b
Match Android OAuth redirect to desktop localhost flow
zortos293 Apr 10, 2026
528cbdc
Revert "Match Android OAuth redirect to desktop localhost flow"
zortos293 Apr 10, 2026
889d9d7
Harden Android localhost auth callback handling
zortos293 Apr 10, 2026
01c6b94
Merge dev into Android Capacitor target
zortos293 Apr 10, 2026
dc2ae3e
Use WebView-based Android OAuth interception
zortos293 Apr 10, 2026
f3703d6
Fix Android auth state after WebView login
zortos293 Apr 11, 2026
2e7bf3d
Align Android session creation with desktop payload
zortos293 Apr 11, 2026
14cb1fd
Merge branch 'dev' into capy/android-capacitor-target
Kief5555 Apr 11, 2026
4f1fdd1
Resolve Package lock issues
Kief5555 Apr 11, 2026
b839606
Fix linter errors
Kief5555 Apr 11, 2026
d7ff05a
Merge origin/dev into capy/android-capacitor-target
zortos293 Apr 17, 2026
75b94ad
Apply Android PR review fixes
zortos293 Apr 17, 2026
e6946d3
Fix Android session parity follow-ups
zortos293 Apr 17, 2026
915c4ff
Fix Android follow-up parity issues
zortos293 Apr 17, 2026
0b83461
Fix Android runtime follow-up regressions
zortos293 Apr 17, 2026
28034b9
Fix Android splash and media write follow-ups
zortos293 Apr 17, 2026
ad9e892
Fix Android polling and packaging follow-ups
zortos293 Apr 17, 2026
ca53b28
Fix Android session conflict and relay follow-ups
zortos293 Apr 17, 2026
f84b464
Fix Android wrapper and relay candidate replay
zortos293 Apr 17, 2026
777d462
Fix avatar fallback escaping and gating
zortos293 Apr 17, 2026
8017b40
Fix Android fullscreen back and ICE fallback
zortos293 Apr 17, 2026
438b2f6
Fix Android signaling endpoint selection
zortos293 Apr 17, 2026
a18064b
Preserve Android active session signaling hosts
zortos293 Apr 18, 2026
c22e682
Scope relay ICE replay to current offer
zortos293 Apr 18, 2026
2f68193
Align Android ad and signaling handling
zortos293 Apr 18, 2026
369fee4
Fix Android parity follow-up issues
zortos293 Apr 18, 2026
02abc96
Refine Android ICE scope handling
zortos293 Apr 18, 2026
0095b6c
Fix Android signaling and fullscreen follow-ups
zortos293 Apr 18, 2026
1c16b18
Fix Android active session and relay issues
zortos293 Apr 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/auto-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,63 @@ jobs:
opennow-stable/dist-release/*.AppImage
opennow-stable/dist-release/*.deb
if-no-files-found: error

android-apk:
name: android-apk
runs-on: ubuntu-24.04

defaults:
run:
working-directory: opennow-stable

env:
npm_config_audit: "false"
npm_config_fund: "false"
ANDROID_COMPILE_SDK: "36"
ANDROID_BUILD_TOOLS: "36.0.0"

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: "**/package-lock.json"

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
cache: gradle

- name: Setup Android SDK
uses: android-actions/setup-android@v3
Comment on lines +142 to +143
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[🟡 Medium] [🟡 Investigate]

android-actions/setup-android only installs the command-line tools and platform-tools by default, but this PR pins the Android project to API 36 in @opennow-stable/android/variables.gradle. That means the new job is only green as long as the hosted Ubuntu image happens to prebundle the required SDK platform/build-tools; on a fresh or rotated runner, ./gradlew assembleDebug will fail before compilation with a missing android-36/build-tools error. Explicitly installing the platform (and matching build-tools) in the workflow makes the Android build reproducible.

# .github/workflows/auto-build.yml
- name: Setup Android SDK
  uses: android-actions/setup-android@v3

- name: Install dependencies
Suggested change
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
packages: "platforms;android-36 build-tools;35.0.0"


- name: Install Android SDK components
run: |
yes | sdkmanager --licenses >/dev/null
sdkmanager \
"platform-tools" \
"platforms;android-${ANDROID_COMPILE_SDK}" \
"build-tools;${ANDROID_BUILD_TOOLS}"

- name: Install dependencies
run: npm ci --prefer-offline --no-audit --progress=false

- name: Build web assets and sync Android project
run: npm run cap:sync:android

- name: Build debug APK
working-directory: opennow-stable/android
run: ./gradlew --no-daemon assembleDebug

- name: Upload Android APK artifact
uses: actions/upload-artifact@v4
with:
name: opennow-stable-android-apk
path: opennow-stable/android/app/build/outputs/apk/debug/app-debug.apk
if-no-files-found: error
43 changes: 37 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,14 @@

## Overview

OpenNOW is a community-built Electron app for playing GeForce NOW from an open-source desktop client. The active implementation lives in [`opennow-stable/`](opennow-stable) and uses Electron, React, and TypeScript across the main, preload, and renderer processes.
OpenNOW is a community-built GeForce NOW client. The active implementation lives in [`opennow-stable/`](opennow-stable) and now supports two runtime targets from the same React renderer: Electron for desktop and Capacitor for Android.

The project aims to give players a transparent, customizable alternative to the official client without hiding the technical parts from contributors.

## Highlights

- Open-source desktop client for Windows, macOS, and Linux
- Experimental Android target via Capacitor using the shared React renderer in a WebView
- Catalog and public game browsing with search and library-aware session handling
- Stream controls for codec, resolution, FPS, aspect ratio, region, and quality preferences
- In-stream diagnostics overlay with latency, packet loss, decode, and render stats
Expand All @@ -81,6 +82,8 @@ Current packaging targets:
| Linux x64 | `AppImage`, `deb` |
| Linux ARM64 | `AppImage`, `deb` |

For Android testing, GitHub Actions now builds a debug APK artifact for manual workflow runs, plus pull requests and pushes to `main`/`dev` when the `auto-build` path filters match (`opennow-stable/**` or `.github/workflows/auto-build.yml`). Download it from the workflow artifacts; it is intended for testing, not release distribution.

### Develop Locally

From the repository root:
Expand Down Expand Up @@ -122,15 +125,43 @@ For a fuller setup guide, see [docs/development.md](docs/development.md).

## Architecture At A Glance

OpenNOW is split into three Electron layers:
OpenNOW uses a shared renderer with thin platform adapters:

| Layer | Tech | Responsibility |
| --- | --- | --- |
| Main | Electron + Node.js | OAuth, CloudMatch/session orchestration, signaling, caching, local file handling |
| Preload | Electron `contextBridge` | Safe IPC bridge between the app shell and UI |
| Renderer | React + TypeScript | Login flow, browsing, settings, WebRTC playback, diagnostics, controls |
| Main | Electron + Node.js | Desktop-only OAuth, IPC, local filesystem/media, cache, window management |
| Preload | Electron `contextBridge` | Desktop bridge exposing the existing OpenNOW API surface |
| Renderer | React + TypeScript | Shared login flow, browsing, settings, WebRTC playback, diagnostics, controls |
| Capacitor Android | Capacitor + WebView | Android shell, localhost WebView auth interception, Preferences/filesystem storage, browser-based signaling |

The code lives under [`opennow-stable/src/`](opennow-stable/src), with shared TypeScript types and platform-neutral helpers in [`opennow-stable/src/shared/`](opennow-stable/src/shared). The renderer now consumes [`src/renderer/src/platform/`](opennow-stable/src/renderer/src/platform/) instead of hard-coding `window.openNow`.

## Android Status

The Android target is an initial pass intended to run the core OpenNOW flow inside a Capacitor WebView. Current Android support includes:

- auth session restore
- login via native Android WebView interception while preserving the exact desktop redirect URI contract (`http://localhost:<port>`)
- provider and region loading
- main/library/public game catalog fetches
- session create, poll, claim, and stop
- direct signaling from the WebView
- settings persistence
- screenshots and recordings stored in the app data directory

Known Android limitations in this pass:

- no desktop-style quit action
- no pointer-lock toggle semantics
- no Electron log export or cache deletion flow
- no show-in-folder integration for media
- screenshot export/save-as remains desktop-only
- some desktop shortcut UX is hidden or non-applicable on touch devices

Android auth now mirrors the desktop localhost redirect contract by opening NVIDIA login in a native Android WebView and intercepting the navigation to `http://localhost:<port>` inside the Android shell instead of using deep links or running a real loopback callback server.

CI also produces a testable Android APK artifact from the Capacitor target so reviewers can install and validate the current branch without making a release build.

The code lives under [`opennow-stable/src/`](opennow-stable/src), with shared TypeScript types and IPC contracts in [`opennow-stable/src/shared/`](opennow-stable/src/shared).

## Contributing

Expand Down
69 changes: 67 additions & 2 deletions docs/development.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# Development Guide

This guide covers the active Electron-based OpenNOW client in [`opennow-stable/`](../opennow-stable).
This guide covers the active OpenNOW app in [`opennow-stable/`](../opennow-stable), including the existing Electron desktop target and the new Capacitor Android target.

## Prerequisites

- Node.js 22 or newer
- npm
- Java 21 JDK
- Android SDK command-line tools or Android Studio
- `ANDROID_SDK_ROOT` set to your local Android SDK path when building the APK outside Android Studio
- A GeForce NOW account for end-to-end testing

## Getting Started
Expand Down Expand Up @@ -35,12 +38,20 @@ npm run dev
npm run preview
npm run typecheck
npm run build
npm run build:web
npm run cap:sync:android
npm run cap:open:android
npm run dist
npm run dist:signed
```

GitHub Actions also builds a testable Android debug APK artifact in the `auto-build` workflow for manual runs, plus pull requests and pushes to `main`/`dev` when the workflow path filters match (`opennow-stable/**` or `.github/workflows/auto-build.yml`).

## Workspace Layout

The Android shell lives in [`opennow-stable/android/`](../opennow-stable/android), Capacitor config lives in [`opennow-stable/capacitor.config.ts`](../opennow-stable/capacitor.config.ts), and the renderer platform abstraction lives in [`opennow-stable/src/renderer/src/platform/`](../opennow-stable/src/renderer/src/platform/).


```text
opennow-stable/
├── src/
Expand Down Expand Up @@ -91,7 +102,8 @@ The renderer is a React app responsible for:
- Browsing the catalog and public listings
- Managing stream launch state and session recovery
- Rendering the WebRTC stream
- Handling controller input, shortcuts, stats overlay, screenshots, recordings, and settings UI
- Handling controller input, stats overlay, screenshots, recordings, and settings UI
- Choosing the active runtime implementation through `src/renderer/src/platform/`

Key entry points:

Expand Down Expand Up @@ -155,10 +167,63 @@ Current build matrix:
| Linux x64 | `AppImage`, `deb` |
| Linux ARM64 | `AppImage`, `deb` |

Additional CI output:

| Target | Output |
| --- | --- |
| Android testing | Debug APK artifact uploaded from `auto-build` |

## Notes For Contributors

- The active app is the Electron client. If you see older references to previous implementations, prefer `opennow-stable/`.
- Root-level npm scripts are convenience wrappers around the `opennow-stable` workspace.
- Before opening a PR, run `npm run typecheck` and `npm run build`.

For contribution workflow details, see [`.github/CONTRIBUTING.md`](../.github/CONTRIBUTING.md).


## Android Workflow

Local Android toolchain prerequisites:

- Android platform `android-36`
- Android build-tools `36.0.0`
- Android platform-tools
- Accepted Android SDK licenses

If you are using the command-line SDK tools, install the same Android components that CI installs:

```bash
yes | sdkmanager --licenses
sdkmanager --install \
Comment thread
capy-ai[bot] marked this conversation as resolved.
"platform-tools" \
"platforms;android-36" \
"build-tools;36.0.0"
```

Build and sync web assets into the Android project:

```bash
cd opennow-stable
npm run cap:sync:android
```

Build a local test APK:

```bash
cd opennow-stable
npm run cap:sync:android
cd android
./gradlew assembleDebug
```

Open the Android project in Android Studio:

```bash
cd opennow-stable
npm run cap:open:android
```

Current Android support is limited to the core cloud-gaming path. Android login now follows the same localhost redirect contract as desktop (`http://localhost:<port>` for both authorize and token exchange), but the Android shell intercepts that navigation inside a native WebView instead of hosting a real localhost callback server. Desktop-specific features such as quit app, pointer-lock toggles, log export, cache deletion, show-in-folder actions, and screenshot save-as are intentionally gated or unavailable on Android in this pass.

For CI-based testing, use the APK artifact uploaded by the `auto-build` workflow. It is a debug/testing package and is not release-signed.
101 changes: 101 additions & 0 deletions opennow-stable/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore

# Built application files
*.apk
*.aar
*.ap_
*.aab

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/
# Uncomment the following line in case you need and you don't have the release build type files in your app
# release/

# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
# Android Studio 3 in .gitignore file.
.idea/caches
.idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
.idea/navEditor.xml

# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
#*.jks
#*.keystore

# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
.cxx/

# Google Services (e.g. APIs or Firebase)
# google-services.json

# Freeline
freeline.py
freeline/
freeline_project_description.json

# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md

# Version control
vcs.xml

# lint
lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/

# Android Profiling
*.hprof

# Cordova plugins for Capacitor
capacitor-cordova-android-plugins

# Copied web assets
app/src/main/assets/public

# Generated Config files
app/src/main/assets/capacitor.config.json
app/src/main/assets/capacitor.plugins.json
app/src/main/res/xml/config.xml
2 changes: 2 additions & 0 deletions opennow-stable/android/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/build/*
!/build/.npmkeep
Loading
Loading