From b5af70664106e7a75dc17602f4b3e5f6e2a575c0 Mon Sep 17 00:00:00 2001 From: Roberto Fontanarosa Date: Tue, 7 Jul 2026 13:11:04 +0200 Subject: [PATCH 1/3] deferred deep link for survey QR code --- ...android-intent-landing-page.component.html | 2 +- .../android-intent-landing-page.component.ts | 24 +++++++++++++++++-- .../navigation/navigation.service.spec.ts | 7 ++++++ .../services/navigation/navigation.service.ts | 5 ++++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html b/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html index 1c787d6dc..ebbb2cc45 100644 --- a/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html +++ b/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html @@ -26,7 +26,7 @@
If it doesn't open automatically, you will be redirected to Google Play to install it.
- + Get in on Google Play= 0 ? (segments[surveyIndex + 1] ?? '') : ''; + } + private isAndroidDevice(): boolean { const userAgent = window.navigator.userAgent || window.navigator.vendor || 'unknown'; @@ -91,11 +105,17 @@ export class AndroidIntentLandingPageComponent implements OnInit { const path = this.router.url; + const surveyId = this.parseSurveyId(path); + + this.playStoreUrl = surveyId + ? this.navigationService.getPlayStoreUrl(googlePlayId, surveyId) + : `https://play.google.com/store/apps/details?id=${googlePlayId}`; + const timeout = 5000; - // Fallback: redirect to Google Play if app doesn't open + // Fallback: if the app didn't open, redirect to Google Play. const redirectTimeoutId = setTimeout(() => { - // window.location.href = `https://play.google.com/store/apps/details?id=${googlePlayId}`; + window.location.href = this.playStoreUrl; }, timeout); // Try opening the app via intent URL diff --git a/web/src/app/services/navigation/navigation.service.spec.ts b/web/src/app/services/navigation/navigation.service.spec.ts index 8e8cfc000..6ccfe633c 100644 --- a/web/src/app/services/navigation/navigation.service.spec.ts +++ b/web/src/app/services/navigation/navigation.service.spec.ts @@ -59,4 +59,11 @@ describe('NavigationService', () => { 'survey/survey123/edit/survey' ); }); + + it('getPlayStoreUrl carries the survey id in the install referrer', () => { + expect(service.getPlayStoreUrl('org.ground.app', 'survey123')).toBe( + 'https://play.google.com/store/apps/details?id=org.ground.app' + + '&referrer=survey_id%3Dsurvey123' + ); + }); }); diff --git a/web/src/app/services/navigation/navigation.service.ts b/web/src/app/services/navigation/navigation.service.ts index 0abf07c5c..d23c7b8d9 100644 --- a/web/src/app/services/navigation/navigation.service.ts +++ b/web/src/app/services/navigation/navigation.service.ts @@ -349,6 +349,11 @@ export class NavigationService implements OnDestroy { return `${this.document.location.origin}/${ANDROID_SEGMENT}/${SURVEY_SEGMENT}/${surveyId}`; } + getPlayStoreUrl(googlePlayId: string, surveyId: string): string { + const referrer = encodeURIComponent(`survey_id=${surveyId}`); + return `https://play.google.com/store/apps/details?id=${googlePlayId}&referrer=${referrer}`; + } + getSidePanelExpanded(): boolean { return this.sidePanelExpanded; } From 8806aa6418fe1e4f833954ac08348c21f171b1e8 Mon Sep 17 00:00:00 2001 From: Roberto Fontanarosa Date: Tue, 7 Jul 2026 13:21:55 +0200 Subject: [PATCH 2/3] centralized google play url string --- .../android-intent-landing-page.component.html | 8 ++++---- .../android-intent-landing-page.component.ts | 11 ++++++++--- web/src/app/services/navigation/navigation.service.ts | 6 ++++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html b/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html index ebbb2cc45..f1c620b31 100644 --- a/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html +++ b/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html @@ -26,11 +26,11 @@
If it doesn't open automatically, you will be redirected to Google Play to install it.
- + Get in on Google Play
diff --git a/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.ts b/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.ts index a04d31e72..8534fba6c 100644 --- a/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.ts +++ b/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.ts @@ -69,6 +69,10 @@ export class AndroidIntentLandingPageComponent implements OnInit { * `/android/survey/{surveyId}`, ignoring any query string or fragment. * Returns an empty string when no survey id is present. */ + getPlayStoreUrl(googlePlayId: string): string { + return this.navigationService.getPlayStoreUrl(googlePlayId); + } + private parseSurveyId(path: string): string { const segments = path.split(/[?#]/)[0].split('/'); const surveyIndex = segments.indexOf(SURVEY_SEGMENT); @@ -107,9 +111,10 @@ export class AndroidIntentLandingPageComponent implements OnInit { const surveyId = this.parseSurveyId(path); - this.playStoreUrl = surveyId - ? this.navigationService.getPlayStoreUrl(googlePlayId, surveyId) - : `https://play.google.com/store/apps/details?id=${googlePlayId}`; + this.playStoreUrl = this.navigationService.getPlayStoreUrl( + googlePlayId, + surveyId + ); const timeout = 5000; diff --git a/web/src/app/services/navigation/navigation.service.ts b/web/src/app/services/navigation/navigation.service.ts index d23c7b8d9..8a78038ed 100644 --- a/web/src/app/services/navigation/navigation.service.ts +++ b/web/src/app/services/navigation/navigation.service.ts @@ -349,9 +349,11 @@ export class NavigationService implements OnDestroy { return `${this.document.location.origin}/${ANDROID_SEGMENT}/${SURVEY_SEGMENT}/${surveyId}`; } - getPlayStoreUrl(googlePlayId: string, surveyId: string): string { + getPlayStoreUrl(googlePlayId: string, surveyId?: string): string { + const url = `https://play.google.com/store/apps/details?id=${googlePlayId}`; + if (!surveyId) return url; const referrer = encodeURIComponent(`survey_id=${surveyId}`); - return `https://play.google.com/store/apps/details?id=${googlePlayId}&referrer=${referrer}`; + return `${url}&referrer=${referrer}`; } getSidePanelExpanded(): boolean { From 13ee2c14480e009c1622e6b8752678917b71ebe5 Mon Sep 17 00:00:00 2001 From: Roberto Fontanarosa Date: Tue, 7 Jul 2026 14:09:52 +0200 Subject: [PATCH 3/3] fixed typo --- .../android-intent-landing-page.component.html | 17 +++++++++++++---- web/src/locale/messages.json | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html b/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html index f1c620b31..8472105cf 100644 --- a/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html +++ b/web/src/app/components/android-intent-landing-page/android-intent-landing-page.component.html @@ -17,19 +17,28 @@
-
Platform Not Supported: We've detected you're using an iOS device. Currently, Ground is only available for Android.
+
+ Platform Not Supported: We've detected you're using an + iOS device. Currently, + Ground is only available for Android. +
-
Launching Ground...
+
+ Launching Ground... +
-
If it doesn't open automatically, you will be redirected to Google Play to install it.
+
+ If it doesn't open automatically, you will be redirected to Google Play + to install it. +
Get in on Google Play diff --git a/web/src/locale/messages.json b/web/src/locale/messages.json index 152b15e50..1b36ed3df 100644 --- a/web/src/locale/messages.json +++ b/web/src/locale/messages.json @@ -9,7 +9,7 @@ "app.texts.platformNotSupported.iosMessage": "{$START_TAG_STRONG}Platform Not Supported:{$CLOSE_TAG_STRONG} We've detected you're using an iOS device. Currently, {$START_TAG_STRONG}Ground is only available for Android.{$CLOSE_TAG_STRONG}", "app.texts.launchingGround": "Launching {$START_TAG_STRONG}Ground{$CLOSE_TAG_STRONG}...", "app.texts.installRedirectMessage": "If it doesn't open automatically, you will be redirected to Google Play to install it.", - "app.labels.googlePlayBadgeAlt": "Get in on Google Play", + "app.labels.googlePlayBadgeAlt": "Get it on Google Play", "app.labels.loadingSurvey": "Loading survey...", "app.labels.goToSurvey": "Go to survey", "app.labels.continue": "Continue",