Skip to content

Commit 20f09c7

Browse files
Merge pull request #1461 from square/zachklipp/fix-mp-runtime
Configure source sets manually, so we can share one for JVM and Android.
2 parents 5ff7eec + 583af66 commit 20f09c7

21 files changed

Lines changed: 284 additions & 30 deletions

File tree

samples/runtime-library/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# runtime-library
2+
3+
This sample tests the gradle config of a jvm-only library that depends on `workflow-runtime`
4+
consumed by an Android app that also depends on `workflow-runtime`.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
plugins {
2+
id("com.android.application")
3+
id("kotlin-android")
4+
id("android-sample-app")
5+
id("android-ui-tests")
6+
alias(libs.plugins.compose.compiler)
7+
id("compose-ui-tests")
8+
}
9+
10+
android {
11+
defaultConfig {
12+
applicationId = "com.squareup.sample.runtimelibrary.app"
13+
multiDexEnabled = true
14+
15+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
16+
}
17+
18+
buildTypes {
19+
release {
20+
signingConfig = signingConfigs.getByName("debug")
21+
isDebuggable = false
22+
}
23+
}
24+
namespace = "com.squareup.sample.runtimelibrary.app"
25+
}
26+
27+
dependencies {
28+
val composeBom = platform(libs.androidx.compose.bom)
29+
30+
// androidTestImplementation(libs.androidx.test.uiautomator)
31+
// androidTestImplementation(libs.squareup.leakcanary.instrumentation)
32+
//
33+
// debugImplementation(libs.squareup.leakcanary.android)
34+
35+
implementation(libs.androidx.activity.ktx)
36+
implementation(libs.androidx.cardview)
37+
// implementation(libs.androidx.constraintlayout)
38+
implementation(libs.androidx.core)
39+
// implementation(libs.androidx.gridlayout)
40+
// Used to side load Baseline Profile when Benchmarking.
41+
// implementation(libs.androidx.profileinstaller)
42+
// implementation(libs.androidx.recyclerview)
43+
// implementation(libs.google.android.material)
44+
implementation(libs.kotlin.common)
45+
implementation(libs.kotlinx.coroutines.core)
46+
implementation(libs.kotlinx.coroutines.rx2)
47+
// implementation(libs.rxjava2.rxandroid)
48+
// implementation(libs.squareup.cycler)
49+
// implementation(libs.squareup.okio)
50+
implementation(composeBom)
51+
implementation(libs.androidx.compose.foundation)
52+
53+
implementation(project(":workflow-runtime"))
54+
// implementation(project(":workflow-ui:core-android"))
55+
// implementation(project(":workflow-ui:core-common"))
56+
implementation(project(":workflow-ui:compose"))
57+
implementation(project(":samples:runtime-library:lib"))
58+
59+
testImplementation(libs.junit)
60+
testImplementation(libs.truth)
61+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<issues format="6" by="lint 8.11.1" type="baseline" client="gradle" dependencies="false" name="AGP (8.11.1)" variant="all" version="8.11.1">
3+
4+
<issue
5+
id="DataExtractionRules"
6+
message="The attribute `android:allowBackup` is deprecated from Android 12 and higher and may be removed in future versions. Consider adding the attribute `android:dataExtractionRules` specifying an `@xml` resource which configures cloud backups and device transfers on Android 12 and higher."
7+
errorLine1=" android:allowBackup=&quot;false&quot;"
8+
errorLine2=" ~~~~~">
9+
<location
10+
file="src/main/AndroidManifest.xml"
11+
line="6"
12+
column="28"/>
13+
</issue>
14+
15+
</issues>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.squareup.sample.runtimelibrary.app
2+
3+
import androidx.compose.ui.test.assertIsDisplayed
4+
import androidx.compose.ui.test.junit4.createAndroidComposeRule
5+
import androidx.compose.ui.test.onNodeWithText
6+
import org.junit.Rule
7+
import org.junit.Test
8+
9+
class AppTest {
10+
11+
@get:Rule val rule = createAndroidComposeRule<AppActivity>()
12+
13+
@Test fun appStarts() {
14+
rule.onNodeWithText("Hello").assertIsDisplayed()
15+
}
16+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<application
6+
android:allowBackup="false"
7+
android:label="@string/app_name"
8+
android:theme="@style/AppTheme"
9+
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon"
10+
>
11+
12+
<activity android:name="com.squareup.sample.runtimelibrary.app.AppActivity"
13+
android:exported="true">
14+
15+
<intent-filter>
16+
<action android:name="android.intent.action.MAIN" />
17+
<category android:name="android.intent.category.LAUNCHER" />
18+
</intent-filter>
19+
20+
</activity>
21+
22+
</application>
23+
</manifest>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.squareup.sample.runtimelibrary.app
2+
3+
import android.os.Bundle
4+
import androidx.activity.viewModels
5+
import androidx.appcompat.app.AppCompatActivity
6+
import androidx.lifecycle.SavedStateHandle
7+
import androidx.lifecycle.ViewModel
8+
import androidx.lifecycle.viewModelScope
9+
import com.squareup.sample.runtimelibrary.lib.checkJvmLinkage
10+
import com.squareup.workflow1.RuntimeConfig
11+
import com.squareup.workflow1.Workflow
12+
import com.squareup.workflow1.WorkflowExperimentalRuntime
13+
import com.squareup.workflow1.android.renderWorkflowIn
14+
import com.squareup.workflow1.config.AndroidRuntimeConfigTools
15+
import com.squareup.workflow1.internal.withKey
16+
import com.squareup.workflow1.ui.ViewEnvironment
17+
import com.squareup.workflow1.ui.compose.withComposeInteropSupport
18+
import com.squareup.workflow1.ui.withEnvironment
19+
import com.squareup.workflow1.ui.workflowContentView
20+
import kotlinx.coroutines.CoroutineScope
21+
import kotlinx.coroutines.flow.StateFlow
22+
import kotlinx.coroutines.flow.map
23+
24+
private val viewEnvironment = ViewEnvironment.EMPTY.withComposeInteropSupport()
25+
26+
class AppActivity : AppCompatActivity() {
27+
28+
override fun onCreate(savedInstanceState: Bundle?) {
29+
super.onCreate(savedInstanceState)
30+
31+
// This method is defined by both Android and JVM targets.
32+
RuntimeException().withKey("foo")
33+
34+
// This makes the same call as above, but is linked with the JVM artifact. If Gradle is
35+
// misconfigured, it'll try to load a different class with the same FQN.
36+
checkJvmLinkage()
37+
38+
// This ViewModel will survive configuration changes. It's instantiated
39+
// by the first call to viewModels(), and that original instance is returned by
40+
// succeeding calls.
41+
val model: AppViewModel by viewModels()
42+
workflowContentView.take(
43+
lifecycle = lifecycle,
44+
renderings = model.renderings
45+
.map { it.withEnvironment(viewEnvironment) }
46+
)
47+
}
48+
49+
@OptIn(WorkflowExperimentalRuntime::class)
50+
class AppViewModel(savedState: SavedStateHandle) : ViewModel() {
51+
val renderings: StateFlow<AppRendering> by lazy {
52+
renderWorkflowIn(
53+
workflow = AppWorkflow,
54+
scope = viewModelScope,
55+
savedStateHandle = savedState,
56+
runtimeConfig = AndroidRuntimeConfigTools.getAppWorkflowRuntimeConfig(),
57+
)
58+
}
59+
}
60+
}
61+
62+
fun <O, R> renderWorkflowInWrapper(
63+
workflow: Workflow<Unit, O, R>,
64+
scope: CoroutineScope,
65+
runtimeConfig: RuntimeConfig,
66+
): StateFlow<R> = renderWorkflowIn(
67+
workflow = workflow,
68+
scope = scope,
69+
runtimeConfig = runtimeConfig,
70+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.squareup.sample.runtimelibrary.app
2+
3+
import androidx.compose.foundation.text.BasicText
4+
import androidx.compose.runtime.Composable
5+
import com.squareup.workflow1.StatelessWorkflow
6+
import com.squareup.workflow1.ui.compose.ComposeScreen
7+
8+
data class AppRendering(val message: String) : ComposeScreen {
9+
@Composable override fun Content() {
10+
BasicText(message)
11+
}
12+
}
13+
14+
object AppWorkflow : StatelessWorkflow<Unit, Nothing, AppRendering>() {
15+
override fun render(
16+
renderProps: Unit,
17+
context: RenderContext<Unit, Nothing>
18+
): AppRendering = AppRendering("Hello")
19+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<resources>
2+
<string name="app_name">Hello Workflow</string>
3+
</resources>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<resources>
2+
3+
<!-- Base application theme. -->
4+
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
5+
<!-- Customize your theme here. -->
6+
</style>
7+
8+
</resources>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
plugins {
2+
id("kotlin-jvm")
3+
}
4+
5+
dependencies {
6+
api(project(":workflow-runtime"))
7+
8+
implementation(libs.kotlin.jdk8)
9+
10+
testImplementation(libs.hamcrest)
11+
testImplementation(libs.junit)
12+
testImplementation(libs.kotlin.test.core)
13+
testImplementation(libs.kotlin.test.jdk)
14+
testImplementation(libs.truth)
15+
16+
testImplementation(project(":workflow-testing"))
17+
}

0 commit comments

Comments
 (0)