Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
69 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
0cbfff8
Enhance Android authentication flow and update dependencies
Kief5555 Apr 22, 2026
8c20049
Add session management enhancements for Android, including new sessio…
Kief5555 Apr 25, 2026
b41bacb
Implement Android catalog caching and UI adjustments for improved per…
Kief5555 Apr 25, 2026
a3bf6bf
Bump version to 0.3.3 in package.json and package-lock.json
Kief5555 Apr 25, 2026
8688baf
Enhance Android build configuration and implement TCP ping functionality
Kief5555 Apr 25, 2026
b143819
Implement virtual gamepad support and enhance error handling UI
Kief5555 Apr 25, 2026
e10bc1f
Implement Android touch controls and mousepad functionality with UI a…
Kief5555 Apr 25, 2026
7569fc0
Add touch mouse tap support to AndroidMousePad and WebRTC client
Kief5555 Apr 26, 2026
3537fe2
Implement text input and key press handling for Android controls; enh…
Kief5555 Apr 27, 2026
eeb6b05
bump build count
Kief5555 Apr 29, 2026
2c6dfaa
Update Android version code to 30007; enhance numeric ID validation a…
Kief5555 May 3, 2026
83bb2fe
Enhance StreamView video handling; update className based on video fr…
Kief5555 May 3, 2026
180714d
Update Android version code to 30008; enhance error handling and logg…
Kief5555 May 3, 2026
2b926f2
Update Android version code to 30009; enhance session handling and er…
Kief5555 May 3, 2026
08b3c3d
Add OpenNowAndroid plugin for immersive fullscreen and pointer captur…
Kief5555 May 5, 2026
1a469be
feat: update Android version code to 30011
Kief5555 May 6, 2026
a791e0e
feat: enhance Android touch controls and gamepad input handling
Kief5555 May 7, 2026
09a5f36
fix: change onResume method visibility to public in MainActivity
Kief5555 May 7, 2026
da6e485
feat: implement pointer capture refresh mechanism in OpenNowAndroidPl…
Kief5555 May 7, 2026
e5ce482
feat: enhance Android compatibility and diagnostics with physical gam…
Kief5555 May 8, 2026
9651ba1
feat: optimize pointer capture handling in StreamView and OpenNowAndr…
Kief5555 May 9, 2026
9e6ce3b
fix: update androidVersionCode to 30013 in gradle.properties
Kief5555 May 9, 2026
ca2ed06
feat: enhance Android support with new features and settings adjustments
Kief5555 May 9, 2026
7ed4787
feat: enhance Android support with new settings and UI adjustments
Kief5555 May 9, 2026
41bf176
feat: update Android pointer capture handling and enhance performance…
Kief5555 May 9, 2026
6ef4f05
feat: implement dark mode support with background color adjustments a…
Kief5555 May 9, 2026
f156d75
feat: add Android performance info retrieval and low power touch cont…
Kief5555 May 9, 2026
661e485
feat(android): update version code and enhance mouse input support
Kief5555 May 9, 2026
ae57cbf
feat(android): enhance touch control support and add ultrawide resolu…
Kief5555 May 9, 2026
d635b61
feat(android): update version code to 30019
Kief5555 May 9, 2026
70e8f87
feat(android): enhance controller navigation and touch handling for A…
Kief5555 May 10, 2026
3f8aea6
feat: implement launch store picker modal and enhance store selection…
Kief5555 May 13, 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
37 changes: 31 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 Down Expand Up @@ -122,15 +123,39 @@ 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, deep links, 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 external browser + deep-link callback
- 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

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
30 changes: 28 additions & 2 deletions docs/development.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 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

Expand Down Expand Up @@ -35,12 +35,18 @@ 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
```

## 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 +97,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 @@ -162,3 +169,22 @@ Current build matrix:
- 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

Build and sync web assets into the Android project:

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

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. 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.
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
54 changes: 54 additions & 0 deletions opennow-stable/android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
apply plugin: 'com.android.application'

android {
namespace = "com.opencouldgaming.opennow"
compileSdk = rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "com.opencouldgaming.opennow"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
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] [🔵 Bug]

The new Android target hard-codes its install metadata instead of following the project version that the existing release workflow already updates in opennow-stable/package.json. gradle // opennow-stable/android/app/build.gradle minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" Because Android upgrades require a monotonically increasing versionCode, every future APK built from this config will still identify as build 1 regardless of the actual release being shipped, so the Android artifact will drift from the repo's release version and normal upgrade/install flows will break once a second real release exists. Derive versionName/versionCode from the same source the release pipeline already uses (for example via Gradle properties injected from package.json or CI) instead of keeping them fixed literals.

versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

repositories {
flatDir{
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
}
}

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
implementation project(':capacitor-android')
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
implementation project(':capacitor-cordova-android-plugins')
}

apply from: 'capacitor.build.gradle'

try {
def servicesJSON = file('google-services.json')
if (servicesJSON.text) {
apply plugin: 'com.google.gms.google-services'
}
} catch(Exception e) {
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
}
25 changes: 25 additions & 0 deletions opennow-stable/android/app/capacitor.build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN

android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
}

apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-app')
implementation project(':capacitor-browser')
implementation project(':capacitor-device')
implementation project(':capacitor-filesystem')
implementation project(':capacitor-http')
implementation project(':capacitor-preferences')
implementation project(':capacitor-status-bar')

}


if (hasProperty('postBuildExtras')) {
postBuildExtras()
}
21 changes: 21 additions & 0 deletions opennow-stable/android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.getcapacitor.myapp;

import static org.junit.Assert.*;

import android.content.Context;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {

@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();

assertEquals("com.getcapacitor.app", appContext.getPackageName());
}
}
Loading
Loading