diff --git a/android/README.md b/android/README.md index 08481276..72e9f9ce 100644 --- a/android/README.md +++ b/android/README.md @@ -116,12 +116,19 @@ npx cap sync android ### Load from site -During local development, open Android Studio project and run the app on an emulator or your physical device. Note that right now you can't use a physical device for the local web version (`10.0.2.2:3000 time out` ) +During local development, open Android Studio project and run the app on an emulator or your physical device. +To use an emulator: ``` npx cap open android ``` +To use a physical device for the local web version, you need your mobile and computer to be on the same network / Wi-Fi and point the URL (`LOCAL_BACKEND_DOMAIN` in the code) to your computer IP address (for example, `192.168.1.3:3000`). You also need to set +``` +export NEXT_PUBLIC_WEBVIEW_DEV_PHONE=1 +``` +Then adb install the app your phone (or simply run it from Android Studio on your phone) and the app should be loading content directly from the local code on your computer. You can make changes in the code and it will refresh instantly on the phone. + Building the Application: 1. Open Android Studio. 2. Click on "Open an existing Android Studio project". @@ -175,6 +182,10 @@ adb install -r app/build/outputs/apk/debug/app-debug.apk ./gradlew assembleRelease ``` +### Release on App Stores + +To release on the app stores, you need to submit the .aab files, which are not signed, instead of APK. Google or Apple will then sign it with their own key. + --- ## 9. Debugging @@ -362,3 +373,17 @@ await admin.messaging().send(message) ``` --- + +## Deep link / custom scheme + +A **custom scheme** is a URL protocol that your app owns. +Example: + +``` +com.compassconnections.app://auth +``` + + +When Android (or iOS) sees a redirect to one of these URLs, it **launches your app** and passes it the URL data. It's useful to open links in the app instead of the browser. For example, if there's a link to Compass on Discord and we click on it on a mobile device that has the app, we want the link to open in the app instead of the browser. + +You register this scheme in your `AndroidManifest.xml` so Android knows which app handles it. diff --git a/docs/webview_oauth_signin.md b/docs/webview_oauth_signin.md deleted file mode 100644 index 4532f8a9..00000000 --- a/docs/webview_oauth_signin.md +++ /dev/null @@ -1,180 +0,0 @@ -# WebView OAuth Sign-in - -How to let a WebView-based app safely complete OAuth, even though Google blocks sign-in *inside* WebViews. - ---- - -## 1. The problem - -Google OAuth refuses to complete inside a WebView. -You’ll get errors like: - -``` -403 disallowed_useragent -or -This browser or app may not be secure -``` - -This is because embedded WebViews can intercept credentials, and Google requires that the sign-in happen in a **real browser** (like Chrome, Safari, Firefox). - -So we must: - -1. Start the login **from inside** the WebView app. -2. Open the Google login page in the **system browser**. -3. After the user finishes signing in, Google redirects to a **custom URL** (deep link or universal link). -4. The app intercepts that redirect, extracts the `code` from it, and injects it back into the WebView. - -That’s the “catch the redirect with a custom scheme or deep link” part. - ---- - -## 2. What a deep link / custom scheme is - -A **custom scheme** is a URL protocol that your app owns. -Example: - -``` -com.compassmeet://auth -``` - -or - -``` -compassmeet://auth -``` - -When Android (or iOS) sees a redirect to one of these URLs, it **launches your app** and passes it the URL data. - -You register this scheme in your `AndroidManifest.xml` so Android knows which app handles it. - ---- - -## 3. - -### Step 1 — Start flow inside the WebView - -Your web code (running inside WebView) does: - -```ts -const params = new URLSearchParams({ - client_id: GOOGLE_CLIENT_ID, - redirect_uri: 'com.compassmeet://auth', // your deep link - response_type: 'code', - scope: 'openid email profile', -}); - -window.open(`https://accounts.google.com/o/oauth2/v2/auth?${params}`, '_system'); -``` - -Here, `_system` (or using Capacitor Browser plugin) opens the **system browser**. - ---- - -### Step 2 — User signs in (in the browser) - -After login, Google redirects to your registered `redirect_uri`, e.g.: - -``` -com.compassmeet://auth?code=4/0AfJohXyZ... -``` - ---- - -### Step 3 — The app intercepts that deep link - -In your **Android app code**, you register an intent filter in `AndroidManifest.xml`: - -```xml - - - - - - -``` - -Then, in your app’s main activity, you listen for deep links. -In java: -```java -@Override -protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - String data = intent.getDataString(); - String payload = new JSONObject().put("data", data).toString(); - bridge.getWebView().post(() -> bridge.getWebView().evaluateJavascript("oauthRedirect(" + payload + ");", null)); -} -``` - -That line emits a custom JavaScript event inside the WebView so your web app can pick it up. - ---- - -### Step 4 — WebView catches redirect event and exchanges the code in backend - -In your web app (TypeScript side): - -```ts -window.addEventListener('oauthRedirect', async (event: any) => { - const url = new URL(event.detail); - const code = url.searchParams.get('code'); - - // fetch backend API - const tokens = await api('...', {code}) -}); -``` - -Backend endpoint -```ts -const tokenResponse = await fetch('https://oauth2.googleapis.com/token', { -method: 'POST', -headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, -body: new URLSearchParams({ - client_id: GOOGLE_CLIENT_ID, - code, - redirect_uri: 'com.compassmeet://auth', - grant_type: 'authorization_code', -}), -}); - -const tokens = await tokenResponse.json(); -console.log('Tokens:', tokens); -``` - - -At this point: - -* You have your `access_token` and `id_token`. -* You can sign into Firebase or use them directly. - ---- - -## 4. Why this works and what makes it safe - -* The login itself happens in Google’s **system browser**, not in your WebView. -* The deep link ensures the token is delivered **only** to your app. - ---- - -## 5. Universal links alternative - -If you want to use a normal HTTPS redirect (e.g. `https://www.compassmeet.com/auth/callback`), you can register it as a **universal link**: - -* User finishes login → redirected to your HTTPS domain. -* That URL is also registered to open your app (via Digital Asset Links JSON). -* Android recognizes it and launches your app instead of loading the page in the browser. -* The rest of the flow is the same. - -However, universal links are more setup-heavy (require hosting a `.well-known/assetlinks.json` file). - ---- - -## 6. Summary - -| Step | What happens | Where | -| ---- | -------------------------------------------------------------- | ----------------- | -| 1 | Open Google OAuth URL | WebView | -| 2 | User signs in | System browser | -| 3 | Browser redirects to deep link (e.g. `com.compassmeet://auth`) | OS → App | -| 4 | App intercepts deep link and injects it into WebView | Native layer | -| 5 | WebView exchanges `code` with backend for tokens | Web app + backend |