From e9d0f1b7407c082acb8754eac91e6ebbe5db9a04 Mon Sep 17 00:00:00 2001 From: OS-ruialves Date: Thu, 5 Mar 2026 10:44:37 +0000 Subject: [PATCH] feat: add third-party LiveUpdates provider support and upgrade dependencies - Add support for custom LiveUpdates managers via setLiveUpdateManager() - Upgrade Capacitor from 7.x to 8.x - Upgrade Android compile/target SDK from 35 to 36 - Upgrade Kotlin from 1.9.25 to 2.1.0 - Upgrade Android Gradle Plugin from 8.7.3 to 8.13.0 - Upgrade Gradle from 8.9 to 9.3.1 - Upgrade Java compatibility from 17 to 21 - Bump minimum SDK from 23 to 24 - Add live-updates-provider dependency --- IonicPortals/build.gradle.kts | 13 ++--- .../main/kotlin/io/ionic/portals/Portal.kt | 53 +++++++++++++++++++ .../kotlin/io/ionic/portals/PortalFragment.kt | 7 ++- TestApp/build.gradle.kts | 16 +++--- TestAppCompose/build.gradle.kts | 18 +++---- build.gradle.kts | 9 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 7 files changed, 87 insertions(+), 31 deletions(-) diff --git a/IonicPortals/build.gradle.kts b/IonicPortals/build.gradle.kts index 9d9ce2c..4a9877d 100644 --- a/IonicPortals/build.gradle.kts +++ b/IonicPortals/build.gradle.kts @@ -10,10 +10,10 @@ if (System.getenv("PORTALS_PUBLISH") == "true") { android { namespace = "io.ionic.portals" - compileSdk = 35 + compileSdk = 36 defaultConfig { - minSdk = 23 + minSdk = 24 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -30,11 +30,11 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } kotlinOptions { - jvmTarget = "17" + jvmTarget = "21" } publishing { singleVariant("release") @@ -44,8 +44,9 @@ android { dependencies { implementation(kotlin("reflect")) - api("com.capacitorjs:core:[7.0.0,7.1.0)") + api("com.capacitorjs:core:[8.0.0,9.0.0)") compileOnly("io.ionic:liveupdates:0.5.5") + compileOnly("io.ionic:live-updates-provider:LOCAL-SNAPSHOT") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") implementation("androidx.core:core-ktx:1.15.0") diff --git a/IonicPortals/src/main/kotlin/io/ionic/portals/Portal.kt b/IonicPortals/src/main/kotlin/io/ionic/portals/Portal.kt index f5f7abe..c93b06b 100644 --- a/IonicPortals/src/main/kotlin/io/ionic/portals/Portal.kt +++ b/IonicPortals/src/main/kotlin/io/ionic/portals/Portal.kt @@ -1,9 +1,17 @@ package io.ionic.portals import android.content.Context +import android.util.Log +import com.getcapacitor.JSObject import com.getcapacitor.Plugin import io.ionic.liveupdates.LiveUpdate import io.ionic.liveupdates.LiveUpdateManager +import io.ionic.liveupdates.data.model.FailResult +import io.ionic.liveupdatesprovider.LiveUpdatesError +import io.ionic.liveupdatesprovider.SyncCallback +import io.ionic.liveupdatesprovider.models.SyncResult +import io.ionic.liveupdatesprovider.LiveUpdatesManager as LiveUpdatesManagerProvider + /** * A class representing a Portal that contains information about the web content to load and any @@ -85,6 +93,11 @@ class Portal(val name: String) { } } + /** + * A LiveUpdate manager, if live updates is being used. + */ + var liveUpdatesManager: LiveUpdatesManagerProvider? = null + /** * Whether to run a live update sync when the portal is added to the manager. */ @@ -309,6 +322,7 @@ class PortalBuilder(val name: String) { private var portalFragmentType: Class = PortalFragment::class.java private var onCreate: (portal: Portal) -> Unit = {} private var liveUpdateConfig: LiveUpdate? = null + private var liveUpdatesManager: LiveUpdatesManagerProvider? = null private var devMode: Boolean = true internal constructor(name: String, onCreate: (portal: Portal) -> Unit) : this(name) { @@ -561,6 +575,44 @@ class PortalBuilder(val name: String) { return this } + /** + * Set a custom [LiveUpdateManager] instance to be used with the Portal. + * + * Example usage (kotlin): + * ```kotlin + * val liveUpdateManager = LiveUpdateManager() + * builder = builder.setLiveUpdateManager(liveUpdateManager) + * ``` + * + * Example usage (java): + * ```java + * LiveUpdateManager liveUpdateManager = new LiveUpdateManager(); + * builder = builder.setLiveUpdateManager(liveUpdateManager); + * ``` + * + * @param liveUpdateManager a custom LiveUpdateManager instance + * @return the instance of the PortalBuilder with the LiveUpdateManager set + */ + @JvmOverloads + fun setLiveUpdateManager(context: Context, liveUpdatesManager: LiveUpdatesManagerProvider, updateOnAppLoad: Boolean = true): PortalBuilder { + this.liveUpdatesManager = liveUpdatesManager + if (updateOnAppLoad) { + liveUpdatesManager.sync( + callback = object : SyncCallback { + override fun onComplete(result: SyncResult) { + Log.d("TestApplication", "Live Update sync complete. Did update: ${result.didUpdate}, latest app dir: ${result.latestAppDirectory}") + } + + override fun onError(error: LiveUpdatesError.SyncFailed) { + Log.e("TestApplication", "Live Update sync failed: ${error.message}") + } + } + + ) + } + return this + } + /** * Set development mode on the Portal which will look for a server URL set by the Portals CLI. * This is set to true by default but can be turned off manually if desired. @@ -598,6 +650,7 @@ class PortalBuilder(val name: String) { portal.initialContext = this.initialContext portal.portalFragmentType = this.portalFragmentType portal.liveUpdateConfig = this.liveUpdateConfig + portal.liveUpdatesManager = this.liveUpdatesManager portal.devMode = this.devMode onCreate(portal) return portal diff --git a/IonicPortals/src/main/kotlin/io/ionic/portals/PortalFragment.kt b/IonicPortals/src/main/kotlin/io/ionic/portals/PortalFragment.kt index 2b73fdb..7e36c97 100644 --- a/IonicPortals/src/main/kotlin/io/ionic/portals/PortalFragment.kt +++ b/IonicPortals/src/main/kotlin/io/ionic/portals/PortalFragment.kt @@ -271,7 +271,7 @@ open class PortalFragment : Fragment { */ fun reload() { if(portal?.liveUpdateConfig != null) { - val latestLiveUpdateFiles = LiveUpdateManager.getLatestAppDirectory(requireContext(), portal?.liveUpdateConfig?.appId!!) + val latestLiveUpdateFiles = portal?.liveUpdatesManager?.latestAppDirectory() ?: LiveUpdateManager.getLatestAppDirectory(requireContext(), portal?.liveUpdateConfig?.appId!!) if (latestLiveUpdateFiles != null) { if (liveUpdateFiles == null || liveUpdateFiles!!.path != latestLiveUpdateFiles.path) { liveUpdateFiles = latestLiveUpdateFiles @@ -285,7 +285,6 @@ open class PortalFragment : Fragment { bridge?.setServerAssetPath(portal?.startDir!!) } } - // Reload the bridge to the existing start url bridge?.reload() } @@ -327,7 +326,7 @@ open class PortalFragment : Fragment { .addWebViewListeners(webViewListeners) if (portal?.liveUpdateConfig != null) { - liveUpdateFiles = LiveUpdateManager.getLatestAppDirectory(requireContext(), portal?.liveUpdateConfig?.appId!!) + liveUpdateFiles = portal?.liveUpdatesManager?.latestAppDirectory() ?: LiveUpdateManager.getLatestAppDirectory(requireContext(), portal?.liveUpdateConfig?.appId!!) bridgeBuilder = if (liveUpdateFiles != null) { if (config == null) { val configFile = File(liveUpdateFiles!!.path + "/capacitor.config.json") @@ -516,4 +515,4 @@ open class PortalFragment : Fragment { } } } -} \ No newline at end of file +} diff --git a/TestApp/build.gradle.kts b/TestApp/build.gradle.kts index cd7bfdd..75949b3 100644 --- a/TestApp/build.gradle.kts +++ b/TestApp/build.gradle.kts @@ -9,7 +9,7 @@ plugins { android { namespace = "io.ionic.portals.testapp" - compileSdk = 35 + compileSdk = 36 buildFeatures { buildConfig = true @@ -18,7 +18,7 @@ android { defaultConfig { applicationId = "io.ionic.portals.testapp" minSdk = 24 - targetSdk = 35 + targetSdk = 36 versionCode = 1 versionName = "1.0" @@ -33,22 +33,24 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "21" } } androidComponents { onVariants { - it.buildConfigFields.put("PORTALS_KEY", BuildConfigField("String", getPortalsKey(), "portals registration key")) + it.buildConfigFields?.put("PORTALS_KEY", BuildConfigField("String", getPortalsKey(), "portals registration key")) } } dependencies { + implementation("io.ionic:live-updates-provider:LOCAL-SNAPSHOT") + implementation(project(":IonicPortals")) implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.fragment:fragment-ktx:1.6.2") @@ -68,4 +70,4 @@ fun getPortalsKey(): String { val properties = Properties() properties.load(FileInputStream(propFile)) return properties.getProperty("portals_key") ?: "" -} \ No newline at end of file +} diff --git a/TestAppCompose/build.gradle.kts b/TestAppCompose/build.gradle.kts index 31b0946..03afab9 100644 --- a/TestAppCompose/build.gradle.kts +++ b/TestAppCompose/build.gradle.kts @@ -5,11 +5,12 @@ import com.android.build.api.variant.BuildConfigField plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.plugin.compose") } android { namespace = "io.ionic.portals.composetestapp" - compileSdk = 35 + compileSdk = 36 buildFeatures { buildConfig = true @@ -18,7 +19,7 @@ android { defaultConfig { applicationId = "io.ionic.portals.composetestapp" minSdk = 24 - targetSdk = 35 + targetSdk = 36 versionCode = 1 versionName = "1.0" @@ -35,18 +36,15 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "21" } buildFeatures { compose = true } - composeOptions { - kotlinCompilerExtensionVersion = "1.5.15" - } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" @@ -56,7 +54,7 @@ android { androidComponents { onVariants { - it.buildConfigFields.put("PORTALS_KEY", + it.buildConfigFields?.put("PORTALS_KEY", BuildConfigField("String", getPortalsKey(), "portals registration key") ) } @@ -88,4 +86,4 @@ fun getPortalsKey(): String { val properties = Properties() properties.load(FileInputStream(propFile)) return properties.getProperty("portals_key") ?: "" -} \ No newline at end of file +} diff --git a/build.gradle.kts b/build.gradle.kts index 5313e01..82db3b3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,8 @@ plugins { } buildscript { - val kotlinVersion = "1.9.25" + //val kotlinVersion = "1.9.25" + val kotlinVersion = "2.1.0" extra.apply { set("kotlinVersion", kotlinVersion) } @@ -27,9 +28,10 @@ buildscript { } classpath("org.jetbrains.dokka:dokka-base:1.7.20") - classpath("com.android.tools.build:gradle:8.7.3") + classpath("com.android.tools.build:gradle:8.13.0") classpath("org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + classpath("org.jetbrains.kotlin:compose-compiler-gradle-plugin:$kotlinVersion") } } @@ -40,6 +42,7 @@ if (System.getenv("PORTALS_PUBLISH") == "true") { allprojects { repositories { + mavenLocal() google() mavenCentral() } @@ -56,4 +59,4 @@ allprojects { // register Clean task tasks.register("clean").configure { delete("build") -} \ No newline at end of file +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3037955..6706572 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon May 08 10:58:01 CDT 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists