Skip to content

Instantly share code, notes, and snippets.

@tcannonfodder
Created August 13, 2025 15:25
Show Gist options
  • Select an option

  • Save tcannonfodder/0b57b405c608b687ae5202a72fa955fb to your computer and use it in GitHub Desktop.

Select an option

Save tcannonfodder/0b57b405c608b687ae5202a72fa955fb to your computer and use it in GitHub Desktop.
Median: Android Deep Linking causes infinite loop on launch
{
"general": {
"userAgentRegexes": [],
"replaceStrings": [],
"publicKey": "$DUMMY_BUNDLE_ID",
"deviceRegKey": "abcd2131343",
"appName": "Punchpass - STAGE",
"initialUrl": "https://app.stagepunchpass.com/",
"keepScreenOn": null,
"screenOrientation": {
"iphone": null,
"ipad": null,
"androidPhone": null,
"androidTablet": null
},
"enableWindowOpen": true,
"userAgentAdd": "median",
"forceUserAgent": "",
"iosUserAgentAdd": "median_ios",
"iosForceUserAgent": "",
"androidUserAgentAdd": "median_android",
"androidForceUserAgent": "",
"languages": [],
"nativeBridgeUrls": [],
"iosBundleId": "co.median.ios.$DUMMY_BUNDLE_ID",
"androidPackageName": "co.median.android.$DUMMY_BUNDLE_ID",
"androidSigningKey": "release",
"injectMedianJS": true,
"forceSessionCookieExpiry": 0,
"iosCustomHeaders": {},
"androidCustomHeaders": {},
"version": 11
},
"navigation": {
"ignorePageFinishedRegexes": [],
"redirects": [],
"iosSettings": {},
"iosPullToRefresh": true,
"androidPullToRefresh": true,
"swipeGestures": true,
"iosConnectionOfflineTime": 10,
"androidConnectionOfflineTime": 10,
"regexInternalExternal": {
"active": true,
"rules": [
{
"mode": "external",
"label": "Non-web links",
"pagesToTrigger": "custom",
"regex": "^(?!https?://).*"
},
{
"mode": "appbrowser",
"label": "Facebook",
"pagesToTrigger": "custom",
"regex": "https?://([-\\w]+\\.)*facebook\\.com.*"
},
{
"mode": "appbrowser",
"label": "Twitter/X",
"pagesToTrigger": "custom",
"regex": "https?://([\\-\\w]+\\.)*(twitter|x)\\.com/.*"
},
{
"mode": "appbrowser",
"label": "Instagram",
"pagesToTrigger": "custom",
"regex": "https?://([-\\w]+\\.)*instagram\\.com/.*"
},
{
"mode": "appbrowser",
"label": "Google Maps",
"pagesToTrigger": "custom",
"regex": "https?://maps\\.google\\.com.*"
},
{
"mode": "appbrowser",
"label": "Google Maps Search",
"pagesToTrigger": "custom",
"regex": "https?://([-\\w]+\\.)*google\\.com/maps/search/.*"
},
{
"mode": "appbrowser",
"label": "LinkedIn",
"pagesToTrigger": "custom",
"regex": "https?://([-\\w]+\\.)*linkedin\\.com/.*"
},
{
"mode": "appbrowser",
"label": "Microsoft Login",
"pagesToTrigger": "custom",
"regex": "https?://login\\.microsoftonline\\.com.*"
},
{
"mode": "internal",
"label": "All pages on my domain",
"pagesToTrigger": "domain",
"regex": "https?:\\/\\/([-\\w]+\\.)*stagepunchpass.com(\\/.*)?$"
},
{
"mode": "appbrowser",
"label": "All Other Links",
"pagesToTrigger": "all",
"regex": ".*"
}
]
},
"deepLinkDomains": {
"enableAndroidApplinks": true,
"domains": [
"*.stagepunchpass.com",
"app.stagepunchpass.com",
"btvfit.stagepunchpass.com"
]
},
"navigationTitles": {
"titles": [
{
"id": "1",
"regex": ".*",
"customTitle": false
}
],
"active": true
},
"iosShowRefreshButton": false,
"androidShowRefreshButton": false,
"actionConfig": {
"actions": [
{
"id": "1",
"items": [
{
"icon": "far fa-qrcode",
"label": "Scan QR Code",
"url": "javascript:window.PunchpassMedian.sendEvent(`scan-qr-code`)",
"system": "javascript"
}
]
}
],
"actionSelection": [
{
"id": "1",
"label": "Top Nav Bar Menu 1 - All Pages",
"regex": ".*",
"custom": false
}
],
"active": true
},
"navigationLevels": {
"active": true,
"levels": []
},
"sidebarNavigation": {
"menuSelectionConfig": {
"redirectLocations": [
{
"regex": ".*",
"menuName": "default",
"loggedIn": true
}
]
},
"menus": [
{
"active": false,
"items": [
{
"url": "https://app.punchpass.com/account/password_resets/new",
"label": "Forgot your password? click here to reset it.",
"subLinks": []
},
{
"url": "https://app.punchpass.com/account/sign_up",
"label": "Don't have a punchpass account? create one here.",
"subLinks": []
},
{
"url": "https://support.punchpass.com/",
"label": "Visit support",
"subLinks": []
}
],
"name": "default"
}
]
},
"tabNavigation": {
"active": true,
"tabMenus": [],
"tabSelectionConfig": []
},
"androidShowOfflinePage": true,
"iosShowOfflinePage": true,
"toolbarNavigation": {
"enabled": true,
"visibilityByPages": "allPages",
"visibilityByBackButton": "backButtonActive",
"regexes": [
{
"enabled": true,
"regex": ".*"
}
],
"items": [
{
"system": "back",
"titleType": "noText",
"visibility": "allPages",
"urlRegex": [
{
"enabled": true,
"regex": ".*"
}
]
},
{
"system": "refresh",
"enabled": true,
"visibility": "allPages",
"urlRegex": [
{
"enabled": true,
"regex": ".*"
}
]
},
{
"system": "forward",
"enabled": true,
"titleType": "noText",
"visibility": "allPages",
"urlRegex": [
{
"enabled": true,
"regex": ".*"
}
]
}
]
},
"maxWindows": {
"enabled": false,
"numWindows": 5,
"autoClose": false
}
},
"styling": {
"splashScreen": {
"ios": {
"backgroundImage": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812066_ajdr3mmbrcv3g_006168_1_2x2.png",
"backgroundImageDark": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812077_q25509uy62a2y_006168_1_2x2.png",
"backgroundColor": "#006168",
"backgroundColorDark": "#006168",
"centerImage": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"centerImageDark": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"animation": null,
"animationDark": null,
"animationFrame": null,
"animationFrameDark": null,
"animationLoop": "once",
"animated": false
},
"android": {
"launchImages": {
"mdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812198_g18fef71c3ctu_180x180.png",
"hdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812207_9h9cfdv5nmuju_270x270.png",
"xhdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812215_2emp4kuwj54qa_360x360.png",
"xxhdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812226_kp926u88yncup_540x540.png",
"xxxhdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812238_zj3j87tz271ya_720x720.png"
},
"launchImagesDark": {
"mdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812249_dedw6hxwfwwaw_180x180.png",
"hdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812273_qj19a5fp89yfp_270x270.png",
"xhdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812301_ydkhnbg47u840_360x360.png",
"xxhdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812319_u1zarkzgwachg_540x540.png",
"xxxhdpi": "https://gonativeio.s3.amazonaws.com/app_files/$DUMMY_BUNDLE_ID/1754318812375_rbp2ad06xhx82_720x720.png"
},
"showSplash": true,
"backgroundColor": "#006168",
"backgroundColorDark": "#006168",
"animation": null,
"animationDark": null,
"animationFrame": null,
"animationFrameDark": null,
"animationLoop": "once",
"animated": false
}
},
"transitionInteractiveDelayMax": 0.2,
"menuAnimationDuration": 0.15,
"iosTheme": "default",
"androidTabPressedBackgroundColor": "#CCCCCC",
"androidTabPressedBackgroundColorDark": "#999999",
"androidBackgroundColor": "#FFFFFF",
"androidBackgroundColorDark": "#333333",
"icon": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"iosIcon": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"customIcons": {},
"iosDarkMode": "auto",
"iosEnableBlurInStatusBar": false,
"iosStatusBarStyle": "auto",
"iosEnableOverlayInStatusBar": false,
"iosStatusBarBackgroundColor": "#f4f2f1",
"iosStatusBarBackgroundColorDark": "#000000",
"androidStatusBarStyle": "auto",
"androidEnableOverlayInStatusBar": false,
"androidStatusBarBackgroundColor": "#5C5C5C",
"androidStatusBarBackgroundColorDark": "#333333",
"iosTintColor": "#006168",
"iosTintColorDark": "#f4f2f1",
"androidIcon": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"androidTheme": "auto",
"androidAccentColor": "#009688",
"androidAccentColorDark": "#80cbc4",
"androidSystemNavBarColor": "#FFFFFF",
"androidSystemNavBarColorDark": "#000000",
"androidPullToRefreshColor": "#1A100B",
"androidPullToRefreshColorDark": "#FFFFFF",
"iosActivityIndicatorColor": "#e50082",
"iosActivityIndicatorColorDark": "#e50082",
"androidActivityIndicatorColor": "#e50082",
"androidActivityIndicatorColorDark": "#e50082",
"androidWebviewTextZoom": null,
"hideWebviewAlpha": 0.5,
"forceViewportWidth": null,
"pinchToZoom": null,
"iosDynamicType": null,
"androidSwipeNavigationBackgroundColor": "#FFFFFF",
"androidSwipeNavigationBackgroundColorDark": "#333333",
"androidSwipeNavigationActiveColor": "#000000",
"androidSwipeNavigationActiveColorDark": "#FFFFFF",
"androidSwipeNavigationInactiveColor": "#666666",
"androidSwipeNavigationInactiveColorDark": "#666666",
"navigationTitleImageLocation": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"navigationTitleImageLocationDark": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"iosTitleColor": "#0E0D08",
"iosTitleColorDark": "#ffffff",
"iosNavigationBarTintColor": "#f8f8f8",
"iosNavigationBarTintColorDark": "#202020",
"androidActionBarBackgroundColor": "#FFFFFF",
"androidActionBarBackgroundColorDark": "#333333",
"androidHeaderImage": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"androidHeaderImageDark": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"androidActionBarForegroundColor": "#1A100B",
"androidActionBarForegroundColorDark": "#FFFFFF",
"iosSidebarBackgroundColor": "#f8f8f8",
"iosSidebarBackgroundColorDark": "#202020",
"iosSidebarFont": "Default",
"iosHeaderImage": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"iosHeaderImageDark": "https://s3.amazonaws.com/gonativeio/app_files/$DUMMY_BUNDLE_ID/app_icon_ios.png",
"iosSidebarTextColor": "#0E0D08",
"iosSidebarTextColorDark": "#ffffff",
"androidSidebarBackgroundColor": "#FFFFFF",
"androidSidebarBackgroundColorDark": "#333333",
"androidSidebarForegroundColor": "#1A100B",
"androidSidebarForegroundColorDark": "#FFFFFF",
"androidSidebarSeparatorColor": "#CCCCCC",
"androidSidebarSeparatorColorDark": "#666666",
"androidSidebarHighlightColor": "#1A100B",
"androidSidebarHighlightColorDark": "#FFFFFF",
"androidShowLogoInSideBar": true,
"androidShowAppNameInSideBar": true,
"androidTabBarBackgroundColor": "#FFFFFF",
"androidTabBarBackgroundColorDark": "#333333",
"androidTabBarTextColor": "#949494",
"androidTabBarTextColorDark": "#FFFFFF",
"androidTabBarIndicatorColor": "#1A100B",
"androidTabBarIndicatorColorDark": "#666666",
"iosTabBarTintColor": "#f8f8f8",
"iosTabBarTintColorDark": "#000000",
"iosTabBarInactiveColor": "#A1A1A1",
"iosTabBarInactiveColorDark": "#818181",
"disableAnimations": false,
"navigationTitleImage": false,
"androidHideTitleInActionBar": false,
"showNavigationBar": false,
"showActionBar": false
},
"allowZoom": null,
"contextMenu": {
"enabled": false,
"linkActions": [
"copyLink",
"openExternal"
]
},
"security": {
"network": {
"allowInsecure": null
}
},
"permissions": {
"usesGeolocation": false,
"iosLocationUsageDescription": "",
"iosCameraUsageDescription": "",
"iosMicrophoneUsageDescription": "",
"enableWebRTCamera": false,
"enableWebRTCMicrophone": false,
"androidDownloadToPublicStorage": false,
"iOSATTUserTrackingDescription": "",
"iOSRequestATTConsentOnLoad": false
},
"developmentTools": {
"enableWebConsoleLogs": false
},
"services": {
"oneSignalV5": {
"active": true,
"applicationId": "xxxx-xxxx-xxx-xxx",
"iosPluginName": "OneSignalV5Plugin"
},
"barcode": {
"active": true,
"iosPluginName": "BarcodeScannerPlugin"
}
}
}
url: https://btvfit.stagepunchpass.com/classes
appConfig.getRedirects():
* -> https://us-central1-gonative-demos.cloudfunctions.net/splash?initialUrl=https%3A%2F%2Fapp.stagepunchpass.com%2F&splashBackgroundColor=-16752280&splashBackgroundColorDark=-16752280&appIcon=https%3A%2F%2Fgonativeio.s3.us-east-1.amazonaws.com%2Fapp_files%2Fqamyxj%2Fapp_icon_ios.png%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Content-Sha256%3DUNSIGNED-PAYLOAD%26X-Amz-Credential%$DUMMY_AWS_CREDENTIALS
See the following YouTube video: https://www.youtube.com/watch?v=s8tQAjn8AOI
// java/co/median/android/UrlNavigation.java
// Around line 255
public boolean shouldOverrideUrlLoadingNoIntercept(final GoNativeWebviewInterface view, final String url,
@SuppressWarnings("SameParameterValue") final boolean noAction) {
// Called as part of the Intent fired from the App Launch, the `url` is: https://btvfit.stagepunchpass.com/classes
// ..
//
// check redirects
if (appConfig.getRedirects() != null) {
String to = appConfig.getRedirects().get(url); // `to` is `null` when running through the first time
if (to == null) to = appConfig.getRedirects().get("*"); // This line is where it gets the fallback rule, see debug output log and video demonstration below
// `to` then points to the fallback URL (us-central1...); which begins the infinite loop. See the video demo
if (to != null && !to.equals(url)) {
if (noAction) return true;
final String destination = to;
// Sets the destinaiton to the wildcard URL, starts an infinite loop of trying to request the fallback page.
mainActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
mainActivity.loadUrl(destination);
}
});
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment