Skip to content

Commit 2d036f1

Browse files
authored
Merge pull request #5 from FeernandoOFF/bugfix/app-attacher-splash
Bugfix/app attacher splash
2 parents ca0d8d3 + b4cedbc commit 2d036f1

8 files changed

Lines changed: 124 additions & 53 deletions

File tree

app/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ dependencies {
5050
implementation(libs.androidx.ui.tooling.preview)
5151
implementation(libs.androidx.material3)
5252
implementation(libs.androidx.datastore.preferences)
53+
implementation(libs.androidx.core.splashscreen)
54+
implementation(libs.timber)
55+
5356
testImplementation(libs.junit)
5457
androidTestImplementation(libs.androidx.junit)
5558
androidTestImplementation(libs.androidx.espresso.core)
5659
androidTestImplementation(platform(libs.androidx.compose.bom))
5760
androidTestImplementation(libs.androidx.ui.test.junit4)
5861
debugImplementation(libs.androidx.ui.tooling)
5962
debugImplementation(libs.androidx.ui.test.manifest)
60-
implementation(libs.timber)
6163
}

app/src/main/AndroidManifest.xml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,21 @@
1313
android:name=".DemoApp"
1414
android:theme="@style/Theme.DebugMenu">
1515
<activity
16-
android:name=".MainActivity"
16+
android:name=".SplashActivity"
1717
android:exported="true"
18-
android:label="@string/app_name"
19-
android:theme="@style/Theme.DebugMenu">
18+
android:theme="@style/Theme.App.Starting">
2019
<intent-filter>
2120
<action android:name="android.intent.action.MAIN"/>
2221

2322
<category android:name="android.intent.category.LAUNCHER"/>
2423
</intent-filter>
2524
</activity>
25+
<activity
26+
android:name=".MainActivity"
27+
android:exported="true"
28+
android:label="@string/app_name"
29+
android:theme="@style/Theme.DebugMenu">
30+
</activity>
2631
</application>
2732

2833
</manifest>
Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,32 @@
11
package com.tapado.debugmenuDemo
22

33
import android.app.Application
4+
import com.tapado.debugmenuDemo.data.demoDataStore
5+
import com.tapadoo.debugmenu.DebugMenuAttacher
6+
import com.tapadoo.debugmenu.analytics.AnalyticsModule
7+
import com.tapadoo.debugmenu.datastore.DataStoreModule
8+
import com.tapadoo.debugmenu.dynamic.DynamicAction
9+
import com.tapadoo.debugmenu.dynamic.DynamicModule
410

511
class DemoApp : Application() {
612

713
override fun onCreate() {
814
super.onCreate()
915

1016
// Demo: Attach the DebugMenu using the Attacher (no Compose dependency required in consumer app)
11-
// DebugMenuAttacher.attachToApplication(
12-
// this,
13-
// listOf(
14-
// AnalyticsModule(),
15-
// DataStoreModule(listOf(this.applicationContext.demoDataStore)),
16-
// DynamicModule(
17-
// title = "Custom Module",
18-
// globalActions = listOf(
19-
// DynamicAction("Global Action 1") {
20-
// // Perform global action
21-
// }
22-
// )
23-
// ),
24-
// ))
17+
DebugMenuAttacher.attachToApplication(
18+
this,
19+
listOf(
20+
AnalyticsModule(),
21+
DataStoreModule(listOf(this.applicationContext.demoDataStore)),
22+
DynamicModule(
23+
title = "Custom Module",
24+
globalActions = listOf(
25+
DynamicAction("Global Action 1") {
26+
// Perform global action
27+
}
28+
)
29+
),
30+
))
2531
}
2632
}

app/src/main/java/com/tapado/debugmenuDemo/MainActivity.kt

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.tapado.debugmenuDemo.data.demoDataStore
1919
import com.tapado.debugmenuDemo.ui.DemoScreen
2020
import com.tapado.debugmenuDemo.ui.DemoViewModel
2121
import com.tapado.debugmenuDemo.ui.theme.DebugMenuTheme
22+
import com.tapadoo.debugmenu.DebugMenuAttacher
2223
import com.tapadoo.debugmenu.DebugMenuOverlay
2324
import com.tapadoo.debugmenu.analytics.AnalyticsModule
2425
import com.tapadoo.debugmenu.datastore.DataStoreModule
@@ -81,32 +82,32 @@ class MainActivity : ComponentActivity() {
8182
} else {
8283
Text("Logged in!")
8384
}
84-
DebugMenuOverlay(
85-
modules = listOf(
86-
DynamicModule(
87-
title = "Custom Module",
88-
globalActions = listOf(
89-
DynamicAction("Global Action 1") {
90-
// Perform global action
91-
},
92-
DynamicAction("Add API Call") {
93-
// Mocking API call / Intercept
94-
DebugNetworkEvents.addEvent(
95-
DebugNetworkRequest.random()
96-
)
97-
}
98-
)
99-
),
100-
AnalyticsModule(),
101-
LoggingModule(),
102-
DataStoreModule(
103-
listOf(
104-
this@MainActivity.applicationContext.demoDataStore
105-
)
106-
),
107-
NetworkModule()
108-
),
109-
)
85+
// DebugMenuOverlay(
86+
// modules = listOf(
87+
// DynamicModule(
88+
// title = "Custom Module",
89+
// globalActions = listOf(
90+
// DynamicAction("Global Action 1") {
91+
// // Perform global action
92+
// },
93+
// DynamicAction("Add API Call") {
94+
// // Mocking API call / Intercept
95+
// DebugNetworkEvents.addEvent(
96+
// DebugNetworkRequest.random()
97+
// )
98+
// }
99+
// )
100+
// ),
101+
// AnalyticsModule(),
102+
// LoggingModule(),
103+
// DataStoreModule(
104+
// listOf(
105+
// this@MainActivity.applicationContext.demoDataStore
106+
// )
107+
// ),
108+
// NetworkModule()
109+
// ),
110+
// )
110111
}
111112
}
112113
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.tapado.debugmenuDemo
2+
3+
import android.content.Intent
4+
import android.os.Bundle
5+
import androidx.activity.ComponentActivity
6+
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
7+
import androidx.lifecycle.lifecycleScope
8+
import kotlinx.coroutines.delay
9+
import kotlinx.coroutines.launch
10+
11+
class SplashActivity : ComponentActivity() {
12+
13+
private var keepSplashScreen = true
14+
15+
override fun onCreate(savedInstanceState: Bundle?) {
16+
val splashScreen = installSplashScreen()
17+
super.onCreate(savedInstanceState)
18+
19+
splashScreen.setKeepOnScreenCondition { keepSplashScreen }
20+
21+
// Some apps reported crashes when having a custom splash activity
22+
lifecycleScope.launch {
23+
delay(2000)
24+
keepSplashScreen = false
25+
startActivity(Intent(this@SplashActivity, MainActivity::class.java))
26+
finish()
27+
}
28+
}
29+
}

app/src/main/res/values/themes.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
33
<style name="Theme.DebugMenu" parent="android:Theme.Material.Light.NoActionBar"/>
4+
5+
<style name="Theme.App.Starting" parent="Theme.SplashScreen">
6+
<item name="windowSplashScreenBackground">#FFFFFF</item>
7+
<item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
8+
<item name="postSplashScreenTheme">@style/Theme.DebugMenu</item>
9+
</style>
410
</resources>

debugMenu/src/main/java/com/tapadoo/debugmenu/DebugMenuAttacher.kt

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,15 @@ import android.view.ViewGroup
66
import android.widget.FrameLayout
77
import androidx.compose.ui.platform.ComposeView
88
import androidx.core.view.ViewCompat
9-
import androidx.datastore.core.DataStore
10-
import androidx.datastore.preferences.core.Preferences
9+
import androidx.lifecycle.LifecycleOwner
10+
import androidx.lifecycle.ViewModelStoreOwner
11+
import androidx.lifecycle.findViewTreeLifecycleOwner
12+
import androidx.lifecycle.findViewTreeViewModelStoreOwner
13+
import androidx.lifecycle.setViewTreeLifecycleOwner
14+
import androidx.lifecycle.setViewTreeViewModelStoreOwner
15+
import androidx.savedstate.SavedStateRegistryOwner
16+
import androidx.savedstate.findViewTreeSavedStateRegistryOwner
17+
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
1118
import com.tapadoo.debugmenu.module.DebugMenuModule
1219

1320
/**
@@ -25,12 +32,7 @@ object DebugMenuAttacher {
2532
) {
2633
application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
2734
override fun onActivityCreated(activity: Activity, savedInstanceState: android.os.Bundle?) {
28-
try {
29-
// When attaching to an app that uses an Activity as a splash screen, it can crash
30-
DebugMenuAttacher.attach(activity, modules, showFab, enableShake)
31-
} catch (e: Exception) {
32-
33-
}
35+
DebugMenuAttacher.attach(activity, modules, showFab, enableShake)
3436
}
3537

3638
override fun onActivityStarted(activity: Activity) {}
@@ -42,7 +44,6 @@ object DebugMenuAttacher {
4244
})
4345
}
4446

45-
4647
@OptIn(androidx.compose.material3.ExperimentalMaterial3Api::class)
4748
@JvmStatic
4849
fun attach(
@@ -52,10 +53,29 @@ object DebugMenuAttacher {
5253
enableShake: Boolean = false,
5354
) = runCatching {
5455
val decor = activity.window?.decorView as? ViewGroup ?: return@runCatching
56+
5557
// Avoid duplicates
5658
val existing = decor.findViewWithTag<FrameLayout>(TAG)
5759
if (existing != null) return@runCatching
5860

61+
// Ensure ViewTree owners are set for Compose.
62+
// Some activities like Splash Screens might not call setContentView(), so these are missing.
63+
if (decor.findViewTreeLifecycleOwner() == null) {
64+
(activity as? LifecycleOwner)?.let {
65+
decor.setViewTreeLifecycleOwner(it)
66+
}
67+
}
68+
if (decor.findViewTreeViewModelStoreOwner() == null) {
69+
(activity as? ViewModelStoreOwner)?.let {
70+
decor.setViewTreeViewModelStoreOwner(it)
71+
}
72+
}
73+
if (decor.findViewTreeSavedStateRegistryOwner() == null) {
74+
(activity as? SavedStateRegistryOwner)?.let {
75+
decor.setViewTreeSavedStateRegistryOwner(it)
76+
}
77+
}
78+
5979
val container = FrameLayout(activity).apply {
6080
layoutParams = FrameLayout.LayoutParams(
6181
ViewGroup.LayoutParams.MATCH_PARENT,

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[versions]
22
agp = "8.12.0"
3+
coreSplashscreen = "1.2.0"
34
kotlin = "2.0.21"
45
coreKtx = "1.17.0"
56
junit = "4.13.2"
@@ -12,6 +13,7 @@ timber = "5.0.1"
1213

1314
[libraries]
1415
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
16+
androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
1517
junit = { group = "junit", name = "junit", version.ref = "junit" }
1618
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
1719
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }

0 commit comments

Comments
 (0)