From c9a31afa35c4fffd423694998c6312a323ebe608 Mon Sep 17 00:00:00 2001 From: Mygod Date: Thu, 28 Sep 2023 19:19:34 -0400 Subject: [PATCH 01/17] Initial draft of app link --- README.md | 5 +++ app/build.gradle.kts | 4 +-- app/src/main/AndroidManifest.xml | 10 ++++++ app/src/main/java/be/mygod/reactmap/App.kt | 3 +- .../be/mygod/reactmap/ConfigDialogFragment.kt | 3 +- .../java/be/mygod/reactmap/MainActivity.kt | 24 +++++++++----- .../mygod/reactmap/webkit/ReactMapFragment.kt | 31 ++++++++++++++++--- app/src/main/res/values/strings.xml | 1 + 8 files changed, 64 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 28c82b7..e73f9dd 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,8 @@ Other features: * More conveniently refresh the webpage when fullscreen. (During network congestion, Chrome HTTP/3 scheduler retries requests at its own pace. Doing a manual refresh overrides this.) * Login button is clicked automatically (Discord login only). * You could make alerts follow location in background. + +## Guide for custom build + +1. Put your domain inside `default_domain` of `app/src/main/res/values/strings.xml`. +2. Build. diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cb963c6..f516f31 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,8 +14,8 @@ android { applicationId = "be.mygod.reactmap" minSdk = 26 targetSdk = 34 - versionCode = 53 - versionName = "0.5.2" + versionCode = 60 + versionName = "0.6.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b9ce4a6..0c7f8cb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -36,6 +36,16 @@ + + + + + + + + + + ()!! } val userManager by lazy { getSystemService()!! } - val activeUrl get() = pref.getString(KEY_ACTIVE_URL, URL_DEFAULT) ?: URL_DEFAULT + val activeUrl get() = pref.getString(KEY_ACTIVE_URL, null) ?: ("https://" + getString(R.string.default_domain)) override fun onCreate() { super.onCreate() diff --git a/app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt b/app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt index 9dd0819..fca8f58 100644 --- a/app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt @@ -47,7 +47,8 @@ class ConfigDialogFragment : AlertDialogFragment(this) { which, _ -> if (which != DialogInterface.BUTTON_POSITIVE) return@setResultListener currentFragment?.terminate() - reactMapFragment() + reactMapFragment(null) } supportFragmentManager.setFragmentResultListener("ReactMapFragment", this) { _, _ -> - reactMapFragment() + reactMapFragment(null) } } + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + handleIntent(intent) + } + private var currentFragment: ReactMapFragment? = null - private fun reactMapFragment() = supportFragmentManager.commit { - replace(R.id.content, ReactMapFragment().also { currentFragment = it }) + private fun reactMapFragment(overrideUri: Uri?) = supportFragmentManager.commit { + replace(R.id.content, ReactMapFragment(overrideUri).also { currentFragment = it }) } - override fun onNewIntent(intent: Intent?) { - super.onNewIntent(intent) + private fun handleIntent(intent: Intent?) { when (intent?.action) { ACTION_CONFIGURE -> startConfigure(false) ACTION_RESTART_GAME -> AlertDialog.Builder(this).apply { @@ -65,6 +71,10 @@ class MainActivity : FragmentActivity() { setNegativeButton("Samsung") { _, _ -> restartGame("com.nianticlabs.pokemongo.ares") } setNeutralButton(android.R.string.cancel, null) }.show() + Intent.ACTION_VIEW -> { + val currentFragment = currentFragment + if (currentFragment == null) reactMapFragment(intent.data) else currentFragment.handleUri(intent.data) + } } } private fun startConfigure(welcome: Boolean) = ConfigDialogFragment().apply { diff --git a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt index 5ebf1a0..ea20e04 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt @@ -47,9 +47,12 @@ import java.net.URLDecoder import java.nio.charset.Charset import java.util.Locale -class ReactMapFragment : Fragment() { +class ReactMapFragment(private val overrideUri: Uri?) : Fragment() { companion object { private val filenameExtractor = "filename=(\"([^\"]+)\"|[^;]+)".toRegex(RegexOption.IGNORE_CASE) + private val vendorJsMatcher = "/vendor-[0-9a-f]{8}\\.js".toRegex() + private val flyToMatcher = "/@/([0-9.-]+)/([0-9.-]+)(?:/([0-9.-]+))?/?".toRegex() + private val mapHijacker = ",this.callInitHooks\\(\\),this._zoomAnimated=".toRegex() private val supportedHosts = setOf("discordapp.com", "discord.com", "telegram.org", "oauth.telegram.org") } @@ -76,8 +79,8 @@ class ReactMapFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { Timber.d("Creating ReactMapFragment") - val activeUrl = app.activeUrl - hostname = Uri.parse(activeUrl).host!! + val activeUrl = overrideUri?.toString() ?: app.activeUrl + hostname = if (overrideUri == null) Uri.parse(activeUrl).host!! else overrideUri.host!! val activity = requireActivity() web = WebView(activity).apply { settings.apply { @@ -170,9 +173,10 @@ class ReactMapFragment : Fragment() { // Since CookieManager.getCookie does not return session cookie on main requests, // we can only edit secondary files "/api/settings" -> handleSettings(request) - else -> if (path?.startsWith("/locales/") == true && path.endsWith("/translation.json")) { + null -> null + else -> if (path.startsWith("/locales/") && path.endsWith("/translation.json")) { handleTranslation(request) - } else null + } else if (vendorJsMatcher.matchEntire(path) != null) handleVendorJs(request) else null } override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean { @@ -253,12 +257,29 @@ class ReactMapFragment : Fragment() { } response } + private fun handleVendorJs(request: WebResourceRequest) = buildResponse(request) { reader -> + mapHijacker.replace(reader.readText(), ",(window._hijackedMap=this).callInitHooks(),this._zoomAnimated=") + } override fun onDestroyView() { super.onDestroyView() web.destroy() } + fun handleUri(uri: Uri?) { + val host = uri?.host ?: return + if (host != hostname) { + hostname = host + return web.loadUrl(uri.toString()) + } + val path = uri.path + if (path.isNullOrEmpty() || path == "/") return + val match = flyToMatcher.matchEntire(path) ?: return web.loadUrl(uri.toString()) + val script = StringBuilder("window._hijackedMap.flyTo([${match.groupValues[1]}, ${match.groupValues[2]}]") + match.groups[3]?.let { script.append(", ${it.value}") } + script.append(')') + web.evaluateJavascript(script.toString(), null) + } fun terminate() { if (Build.VERSION.SDK_INT >= 29 && web.webViewRenderProcess?.terminate() == false) Timber.w(Exception( "Termination failed")) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 818345a..6e3fc3a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,4 @@ ReactMap + www.reactmap.dev From 08256d70e56b3da6b342b571806b8d622a42cf8b Mon Sep 17 00:00:00 2001 From: Mygod Date: Thu, 28 Sep 2023 19:29:43 -0400 Subject: [PATCH 02/17] Add instructions for supporting multiple domains --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e73f9dd..2fb0981 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,5 @@ Other features: ## Guide for custom build 1. Put your domain inside `default_domain` of `app/src/main/res/values/strings.xml`. -2. Build. +2. If you want to support more domains, edit `app/src/main/AndroidManifest.xml`: find the line `` and add more domains by adding lines like ``. +3. Build. From d4554e83fd800647b5c8c3420b526c4733a24944 Mon Sep 17 00:00:00 2001 From: Mygod Date: Thu, 28 Sep 2023 21:15:38 -0400 Subject: [PATCH 03/17] Fix crash on recreate --- app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt index ea20e04..8ab14e4 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt @@ -47,7 +47,7 @@ import java.net.URLDecoder import java.nio.charset.Charset import java.util.Locale -class ReactMapFragment(private val overrideUri: Uri?) : Fragment() { +class ReactMapFragment @JvmOverloads constructor(private val overrideUri: Uri? = null) : Fragment() { companion object { private val filenameExtractor = "filename=(\"([^\"]+)\"|[^;]+)".toRegex(RegexOption.IGNORE_CASE) private val vendorJsMatcher = "/vendor-[0-9a-f]{8}\\.js".toRegex() From 7ae67e56f6f44aa90ef5a662cb95e5e338038803 Mon Sep 17 00:00:00 2001 From: Mygod Date: Thu, 28 Sep 2023 23:32:31 -0400 Subject: [PATCH 04/17] Ensure that uri is only handled after created --- .../mygod/reactmap/webkit/ReactMapFragment.kt | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt index 8ab14e4..754c474 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt @@ -29,6 +29,7 @@ import androidx.fragment.app.setFragmentResult import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.withCreated import be.mygod.reactmap.App.Companion.app import be.mygod.reactmap.follower.BackgroundLocationReceiver import be.mygod.reactmap.util.CreateDynamicDocument @@ -266,19 +267,21 @@ class ReactMapFragment @JvmOverloads constructor(private val overrideUri: Uri? = web.destroy() } - fun handleUri(uri: Uri?) { - val host = uri?.host ?: return - if (host != hostname) { - hostname = host - return web.loadUrl(uri.toString()) + fun handleUri(uri: Uri?) = uri?.host?.let { host -> + lifecycleScope.launch { + withCreated { } + if (host != hostname) { + hostname = host + return@launch web.loadUrl(uri.toString()) + } + val path = uri.path + if (path.isNullOrEmpty() || path == "/") return@launch + val match = flyToMatcher.matchEntire(path) ?: return@launch web.loadUrl(uri.toString()) + val script = StringBuilder("window._hijackedMap.flyTo([${match.groupValues[1]}, ${match.groupValues[2]}]") + match.groups[3]?.let { script.append(", ${it.value}") } + script.append(')') + web.evaluateJavascript(script.toString(), null) } - val path = uri.path - if (path.isNullOrEmpty() || path == "/") return - val match = flyToMatcher.matchEntire(path) ?: return web.loadUrl(uri.toString()) - val script = StringBuilder("window._hijackedMap.flyTo([${match.groupValues[1]}, ${match.groupValues[2]}]") - match.groups[3]?.let { script.append(", ${it.value}") } - script.append(')') - web.evaluateJavascript(script.toString(), null) } fun terminate() { if (Build.VERSION.SDK_INT >= 29 && web.webViewRenderProcess?.terminate() == false) Timber.w(Exception( From f550f7b62a6fcabc0841706d9022f128989be612 Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 15:22:42 -0400 Subject: [PATCH 05/17] Remove defaultDomain from resources which might be public --- README.md | 2 +- app/build.gradle.kts | 5 +++++ app/src/main/AndroidManifest.xml | 2 +- app/src/main/java/be/mygod/reactmap/App.kt | 2 +- app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt | 3 +-- app/src/main/res/values/strings.xml | 1 - gradle.properties | 3 +++ gradle/libs.versions.toml | 2 +- 8 files changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2fb0981..173d2ed 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,6 @@ Other features: ## Guide for custom build -1. Put your domain inside `default_domain` of `app/src/main/res/values/strings.xml`. +1. Put your domain inside `reactmap.defaultDomain` of `gradle.properties`. 2. If you want to support more domains, edit `app/src/main/AndroidManifest.xml`: find the line `` and add more domains by adding lines like ``. 3. Build. diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f516f31..40ecc52 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,6 +18,11 @@ android { versionName = "0.6.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + extra["reactmap.defaultDomain"]!!.let { defaultDomain -> + manifestPlaceholders["defaultDomain"] = defaultDomain + buildConfigField("String", "DEFAULT_DOMAIN", "\"$defaultDomain\"") + } } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0c7f8cb..6c6ef4f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -44,7 +44,7 @@ - + ()!! } val userManager by lazy { getSystemService()!! } - val activeUrl get() = pref.getString(KEY_ACTIVE_URL, null) ?: ("https://" + getString(R.string.default_domain)) + val activeUrl get() = pref.getString(KEY_ACTIVE_URL, null) ?: "https://${BuildConfig.DEFAULT_DOMAIN}" override fun onCreate() { super.onCreate() diff --git a/app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt b/app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt index fca8f58..dfe5328 100644 --- a/app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/ConfigDialogFragment.kt @@ -47,8 +47,7 @@ class ConfigDialogFragment : AlertDialogFragment ReactMap - www.reactmap.dev diff --git a/gradle.properties b/gradle.properties index c3e0905..82ddb13 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,3 +23,6 @@ kotlin.code.style=official android.nonTransitiveRClass=true android.enableResourceOptimizations=false android.enableVcsInfo=true + +# ReactMap settings for customized build +reactmap.defaultDomain=www.reactmap.dev diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e6bb32f..b1eb174 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] activity = "1.8.0-rc01" -agp = "8.3.0-alpha05" +agp = "8.3.0-alpha06" androidx-test-ext-junit = "1.1.5" browser = "1.6.0" core = "1.12.0" From de2c1b69f3bf3b12ac1d7cda1e35ad23a4e85bc6 Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 15:25:23 -0400 Subject: [PATCH 06/17] Remove useless started --- .../java/be/mygod/reactmap/webkit/SiteController.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/be/mygod/reactmap/webkit/SiteController.kt b/app/src/main/java/be/mygod/reactmap/webkit/SiteController.kt index 759505d..65c14c1 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/SiteController.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/SiteController.kt @@ -7,6 +7,7 @@ import android.graphics.drawable.Icon import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import be.mygod.reactmap.App.Companion.app import be.mygod.reactmap.MainActivity @@ -21,7 +22,7 @@ class SiteController(private val fragment: Fragment) : DefaultLifecycleObserver } private val requestPermission = fragment.registerForActivityResult(ActivityResultContracts.RequestPermission()) { - if (!it || !started) return@registerForActivityResult + if (!it || !fragment.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return@registerForActivityResult val context = fragment.requireContext() app.nm.notify(1, Notification.Builder(context, CHANNEL_ID).apply { setWhen(0) @@ -42,21 +43,20 @@ class SiteController(private val fragment: Fragment) : DefaultLifecycleObserver PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)).build()) }.build()) } - private var started = false var title: String? = null set(value) { field = value - if (started) requestPermission.launch(android.Manifest.permission.POST_NOTIFICATIONS) + if (fragment.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { + requestPermission.launch(android.Manifest.permission.POST_NOTIFICATIONS) + } } override fun onStart(owner: LifecycleOwner) { - started = true if (title != null) requestPermission.launch(android.Manifest.permission.POST_NOTIFICATIONS) } override fun onStop(owner: LifecycleOwner) { - started = false app.nm.cancel(1) } } From 3953082cadca176b718480956aa99cb426475b2e Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 15:36:41 -0400 Subject: [PATCH 07/17] Always show SiteController notif --- .../java/be/mygod/reactmap/webkit/SiteController.kt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/be/mygod/reactmap/webkit/SiteController.kt b/app/src/main/java/be/mygod/reactmap/webkit/SiteController.kt index 65c14c1..c5a99fe 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/SiteController.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/SiteController.kt @@ -27,7 +27,7 @@ class SiteController(private val fragment: Fragment) : DefaultLifecycleObserver app.nm.notify(1, Notification.Builder(context, CHANNEL_ID).apply { setWhen(0) setCategory(Notification.CATEGORY_SERVICE) - setContentTitle(title) + setContentTitle(title ?: "Loading…") setContentText("Tap to configure") setColor(context.getColor(R.color.main_blue)) setGroup(CHANNEL_ID) @@ -52,11 +52,7 @@ class SiteController(private val fragment: Fragment) : DefaultLifecycleObserver } } - override fun onStart(owner: LifecycleOwner) { - if (title != null) requestPermission.launch(android.Manifest.permission.POST_NOTIFICATIONS) - } - - override fun onStop(owner: LifecycleOwner) { - app.nm.cancel(1) - } + override fun onStart(owner: LifecycleOwner) = + requestPermission.launch(android.Manifest.permission.POST_NOTIFICATIONS) + override fun onStop(owner: LifecycleOwner) = app.nm.cancel(1) } From 5b0b0d081214fbd7f0b41269f0ef251fa51c4caa Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 16:51:16 -0400 Subject: [PATCH 08/17] Format AndroidManifest.xml --- app/src/main/AndroidManifest.xml | 36 +++++++++++++++++--------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6c6ef4f..49fd066 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,12 +2,12 @@ - + - + @@ -38,12 +38,12 @@ + - @@ -53,7 +53,7 @@ android:enabled="false" android:exported="false"> - + @@ -62,55 +62,57 @@ + tools:replace="android:directBootAware" /> + tools:replace="android:directBootAware" /> + tools:node="merge" /> + + tools:replace="android:directBootAware" /> + tools:replace="android:directBootAware" /> + tools:replace="android:directBootAware" /> + tools:replace="android:directBootAware" /> + tools:replace="android:directBootAware" /> + tools:replace="android:directBootAware" /> + tools:replace="android:directBootAware" /> + tools:replace="android:directBootAware" /> + + tools:node="remove" /> + tools:node="remove" /> From 2dd93f8f82330c3ad07226e369c43218046118c6 Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 17:02:00 -0400 Subject: [PATCH 09/17] Support custom packageName --- README.md | 4 ++-- app/build.gradle.kts | 4 ++-- app/src/main/res/values/google-services.xml | 10 ++++++++++ gradle.properties | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/values/google-services.xml diff --git a/README.md b/README.md index 173d2ed..fcbea5c 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,6 @@ Other features: ## Guide for custom build -1. Put your domain inside `reactmap.defaultDomain` of `gradle.properties`. -2. If you want to support more domains, edit `app/src/main/AndroidManifest.xml`: find the line `` and add more domains by adding lines like ``. +1. Customize `reactmap.defaultDomain` and `reactmap.packageName` in `gradle.properties`. +2. If you want to support more domains, edit `app/src/main/AndroidManifest.xml`: find the line `` and add more domains by adding lines like ``. 3. Build. diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 40ecc52..42158ce 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,7 +1,7 @@ plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.firebaseCrashlytics) - alias(libs.plugins.googleServices) +// alias(libs.plugins.googleServices) alias(libs.plugins.kotlinAndroid) id("kotlin-parcelize") } @@ -11,7 +11,7 @@ android { compileSdk = 34 defaultConfig { - applicationId = "be.mygod.reactmap" + applicationId = extra["reactmap.packageName"] as String? minSdk = 26 targetSdk = 34 versionCode = 60 diff --git a/app/src/main/res/values/google-services.xml b/app/src/main/res/values/google-services.xml new file mode 100644 index 0000000..f9feea1 --- /dev/null +++ b/app/src/main/res/values/google-services.xml @@ -0,0 +1,10 @@ + + + 53628743953-u05270s2od1es37b9pdrvmn10q6aa3iu.apps.googleusercontent.com + 53628743953 + AIzaSyDlBEXzi1_Kf0kY6cdxexhHfuxyrxx5ZB0 + 1:53628743953:android:ef886035becf4f5adb1cb0 + AIzaSyDlBEXzi1_Kf0kY6cdxexhHfuxyrxx5ZB0 + reactmap-android.appspot.com + reactmap-android + diff --git a/gradle.properties b/gradle.properties index 82ddb13..d95f425 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,3 +26,4 @@ android.enableVcsInfo=true # ReactMap settings for customized build reactmap.defaultDomain=www.reactmap.dev +reactmap.packageName=be.mygod.reactmap From 162c7131961dc02b21551ee19f1b0243684c67be Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 17:08:46 -0400 Subject: [PATCH 10/17] Add comment --- app/build.gradle.kts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 42158ce..3def944 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,9 +1,11 @@ plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.firebaseCrashlytics) -// alias(libs.plugins.googleServices) alias(libs.plugins.kotlinAndroid) id("kotlin-parcelize") + + // https://developers.google.com/android/guides/google-services-plugin#processing_the_json_file +// alias(libs.plugins.googleServices) } android { From 87f2f9eb2111c9e1e1d33f98ceceed017e3b09e8 Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 17:43:48 -0400 Subject: [PATCH 11/17] Fix assembleRelease --- app/build.gradle.kts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3def944..275c91c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,11 +1,12 @@ +import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension + plugins { alias(libs.plugins.androidApplication) + // https://developers.google.com/android/guides/google-services-plugin#processing_the_json_file +// alias(libs.plugins.googleServices) alias(libs.plugins.firebaseCrashlytics) alias(libs.plugins.kotlinAndroid) id("kotlin-parcelize") - - // https://developers.google.com/android/guides/google-services-plugin#processing_the_json_file -// alias(libs.plugins.googleServices) } android { @@ -34,6 +35,9 @@ android { release { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + if (!pluginManager.hasPlugin("com.google.gms.google-services")) { + the().mappingFileUploadEnabled = false + } } } buildFeatures.buildConfig = true From c021d4f85d89c7588642a3e87cec9e8ce27773ed Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 18:01:40 -0400 Subject: [PATCH 12/17] Add support for reactmap.appName --- app/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 275c91c..02d90a8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,6 +22,7 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + if (extra.has("reactmap.appName")) resValue("string", "app_name", extra["reactmap.appName"] as String) extra["reactmap.defaultDomain"]!!.let { defaultDomain -> manifestPlaceholders["defaultDomain"] = defaultDomain buildConfigField("String", "DEFAULT_DOMAIN", "\"$defaultDomain\"") From c01b57c1a73346b3378065e9d2e2fa0156f79172 Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 29 Sep 2023 20:31:24 -0400 Subject: [PATCH 13/17] Fix withCreated again --- app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt index 754c474..6ea634d 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt @@ -268,7 +268,7 @@ class ReactMapFragment @JvmOverloads constructor(private val overrideUri: Uri? = } fun handleUri(uri: Uri?) = uri?.host?.let { host -> - lifecycleScope.launch { + viewLifecycleOwner.lifecycleScope.launch { withCreated { } if (host != hostname) { hostname = host From e6e118a13a7519603de31a551f4a35b5c885e34a Mon Sep 17 00:00:00 2001 From: Mygod Date: Sat, 30 Sep 2023 15:15:07 -0400 Subject: [PATCH 14/17] Minor fixes --- app/build.gradle.kts | 2 +- app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 02d90a8..7dca602 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,9 +2,9 @@ import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension plugins { alias(libs.plugins.androidApplication) + alias(libs.plugins.firebaseCrashlytics) // https://developers.google.com/android/guides/google-services-plugin#processing_the_json_file // alias(libs.plugins.googleServices) - alias(libs.plugins.firebaseCrashlytics) alias(libs.plugins.kotlinAndroid) id("kotlin-parcelize") } diff --git a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt index 6ea634d..ca67096 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt @@ -270,6 +270,7 @@ class ReactMapFragment @JvmOverloads constructor(private val overrideUri: Uri? = fun handleUri(uri: Uri?) = uri?.host?.let { host -> viewLifecycleOwner.lifecycleScope.launch { withCreated { } + Timber.d("Handling URI $uri") if (host != hostname) { hostname = host return@launch web.loadUrl(uri.toString()) From 572b6e4fa5316a678c9150c3ba38ab98a514a7d2 Mon Sep 17 00:00:00 2001 From: Mygod Date: Sat, 30 Sep 2023 15:21:04 -0400 Subject: [PATCH 15/17] Catch IOException on intercepted connections --- .../main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt index ca67096..12dea84 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/ReactMapFragment.kt @@ -207,13 +207,13 @@ class ReactMapFragment @JvmOverloads constructor(private val overrideUri: Uri? = return web } - private fun buildResponse(request: WebResourceRequest, transform: (Reader) -> String): WebResourceResponse { + private fun buildResponse(request: WebResourceRequest, transform: (Reader) -> String) = try { val url = request.url.toString() val conn = ReactMapHttpEngine.openConnection(url) { requestMethod = request.method for ((key, value) in request.requestHeaders) addRequestProperty(key, value) } - return WebResourceResponse(conn.contentType?.substringBefore(';'), conn.contentEncoding, conn.responseCode, + WebResourceResponse(conn.contentType?.substringBefore(';'), conn.contentEncoding, conn.responseCode, conn.responseMessage.let { if (it.isNullOrBlank()) "N/A" else it }, conn.headerFields.mapValues { (_, value) -> value.joinToString() }, if (conn.responseCode in 200..299) try { @@ -225,6 +225,9 @@ class ReactMapFragment @JvmOverloads constructor(private val overrideUri: Uri? = Timber.d(e) conn.inputStream } else conn.findErrorStream) + } catch (e: IOException) { + Timber.d(e) + null } private fun handleSettings(request: WebResourceRequest) = buildResponse(request) { reader -> val response = reader.readText() From c281026a8c701ca20ad3a3dc935b38d0a994b38c Mon Sep 17 00:00:00 2001 From: Mygod Date: Sun, 1 Oct 2023 22:30:39 -0400 Subject: [PATCH 16/17] Do not show badge for select notifs --- app/src/main/java/be/mygod/reactmap/App.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/mygod/reactmap/App.kt b/app/src/main/java/be/mygod/reactmap/App.kt index fc4f82c..5557822 100644 --- a/app/src/main/java/be/mygod/reactmap/App.kt +++ b/app/src/main/java/be/mygod/reactmap/App.kt @@ -78,13 +78,17 @@ class App : Application() { NotificationChannel(SiteController.CHANNEL_ID, "Full screen site controls", NotificationManager.IMPORTANCE_LOW).apply { lockscreenVisibility = Notification.VISIBILITY_SECRET + setShowBadge(false) }, NotificationChannel(LocationSetter.CHANNEL_ID, "Background location updating", NotificationManager.IMPORTANCE_LOW).apply { lockscreenVisibility = Notification.VISIBILITY_PUBLIC + setShowBadge(false) }, NotificationChannel(LocationSetter.CHANNEL_ID_SUCCESS, "Background location updated", - NotificationManager.IMPORTANCE_MIN), + NotificationManager.IMPORTANCE_MIN).apply { + setShowBadge(false) + }, NotificationChannel(LocationSetter.CHANNEL_ID_ERROR, "Background location update failed", NotificationManager.IMPORTANCE_HIGH).apply { enableLights(true) From 674459d03bf85e176106b990490eacb07378d1af Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 2 Oct 2023 12:02:56 -0400 Subject: [PATCH 17/17] Update build instructions --- LICENSE | 2 +- README.md | 45 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index 261eeb9..45dd5c1 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2023 Mygod Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index fcbea5c..77531c6 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,45 @@ Other features: ## Guide for custom build -1. Customize `reactmap.defaultDomain` and `reactmap.packageName` in `gradle.properties`. -2. If you want to support more domains, edit `app/src/main/AndroidManifest.xml`: find the line `` and add more domains by adding lines like ``. -3. Build. +### Setup instructions + +1. If you have not already, generate a signing key with [`keytool`](https://developer.android.com/build/building-cmdline#sign_cmdline). + Using [RSA with a key length of 4096, 8192, or 16384 bits](https://github.com/google/bundletool/blob/0b9149c283e2df73850da670f2130a732639283d/src/main/java/com/android/tools/build/bundletool/commands/AddTransparencyCommand.java#L97) is recommended. +2. Create the following file at `https://mymap.com/.well-known/assetlinks.json` by creating the file in `/path/to/reactmap/public/.well-known/assetlinks.json`: + ```json + [ + { + "relation": [ + "delegate_permission/common.handle_all_urls" + ], + "target": { + "namespace": "android_app", + "package_name": "be.mygod.reactmap.com.mymap", + "sha256_cert_fingerprints": [ + "insert your sha256 cert fingerprint" + ] + } + } + ] + ``` + where the fingerprint can be obtained via `keytool -list -v -keystore /path/to/keystore`. + (If you prefer to using Android Studio to create this file with a wizard, see [here]( https://developer.android.com/studio/write/app-link-indexing#associatesite) for instructions.) +3. (Optional) Make modifications to the source code if you wish. + +### Build instructions + +Build with [injected properties](https://stackoverflow.com/a/47356720/2245107) (modifying these values as you wish): +``` +./gradlew assembleRelease \ + -Pandroid.injected.signing.store.file=$KEYFILE \ + -Pandroid.injected.signing.store.password=$STORE_PASSWORD \ + -Pandroid.injected.signing.key.alias=$KEY_ALIAS \ + -Pandroid.injected.signing.key.password=$KEY_PASSWORD \ + -Preactmap.defaultHost=mymap.com \ + -Preactmap.packageName=be.mygod.reactmap.com.mymap +``` + +Optionally you can also inject `reactmap.appName`. +An alternative to using `-P` switches is to adding your properties to the `gradle.properties` file in the root directory. + +Success! Find your apk in `app/build/outputs/apk/release`.