Skip to content

Commit

Permalink
feat: support the portals CLI functionality for android serve (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
carlpoole authored Mar 12, 2024
1 parent d0253eb commit 656d8bc
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 4 deletions.
68 changes: 68 additions & 0 deletions IonicPortals/src/main/kotlin/io/ionic/portals/DevConfiguration.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.ionic.portals

import android.content.Context
import com.getcapacitor.CapConfig

/**
* This class is used to load the server URL and Capacitor configuration from the assets folder when the app
* is being run in developer mode with the Portals CLI.
*/
object DevConfiguration {

/**
* Get the server URL for the given portal name from the developer mode assets folder.
*/
fun getServerUrl(context: Context, portalName: String): String? {
val portalDirName = "$portalName.debug"
val generalDirName = "portal.debug"
val urlFileName = "url"

val assetManager = context.assets
var serverUrl = try {
assetManager.open("$portalDirName/$urlFileName").bufferedReader().use {
it.readText()
}
} catch (e: Exception) {
null
}

if (serverUrl == null) {
serverUrl = try {
assetManager.open("$generalDirName/$urlFileName").bufferedReader().use {
it.readText()
}
} catch (e: Exception) {
null
}
}

return serverUrl
}

/**
* Get the Capacitor configuration for the given portal name from the developer mode assets folder.
*/
fun getCapacitorConfig(context: Context, portalName: String): CapConfig? {
val portalDirName = "$portalName.debug"
val generalDirName = "portal.debug"
val capConfigFileName = "capacitor.config.json"

var serverConfig = try {
val configFile = context.assets.open("$portalDirName/$capConfigFileName")
CapConfig.loadFromAssets(context, portalDirName)
} catch (e: Exception) {
null
}

if (serverConfig == null) {
serverConfig = try {
val configFile = context.assets.open("$generalDirName/$capConfigFileName")
CapConfig.loadFromAssets(context, generalDirName)
} catch (e: Exception) {
null
}
}

return serverConfig
}
}
21 changes: 20 additions & 1 deletion IonicPortals/src/main/kotlin/io/ionic/portals/Portal.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ class Portal(val name: String) {
var startDir: String = ""
get() = if (field.isEmpty()) name else field

/**
* If the Portal should be loaded in development mode and look for a server URL.
*/
var devMode: Boolean = true

/**
* A LiveUpdate config, if live updates is being used.
*/
Expand Down Expand Up @@ -304,9 +309,10 @@ class PortalBuilder(val name: String) {
private var portalFragmentType: Class<out PortalFragment?> = PortalFragment::class.java
private var onCreate: (portal: Portal) -> Unit = {}
private var liveUpdateConfig: LiveUpdate? = null
private var devMode: Boolean = true

internal constructor(name: String, onCreate: (portal: Portal) -> Unit) : this(name) {
this.onCreate = onCreate;
this.onCreate = onCreate
}

/**
Expand Down Expand Up @@ -555,6 +561,18 @@ class PortalBuilder(val name: String) {
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.
*
* @param devMode if the Portal should be loaded in development mode
* @return the instance of the PortalBuilder with the development mode set
*/
fun setDevMode(devMode: Boolean): PortalBuilder {
this.devMode = devMode
return this
}

/**
* Creates the [Portal] instance from the current state of the [PortalBuilder] provided.
* This finishes building the Portal.
Expand All @@ -580,6 +598,7 @@ class PortalBuilder(val name: String) {
portal.initialContext = this.initialContext
portal.portalFragmentType = this.portalFragmentType
portal.liveUpdateConfig = this.liveUpdateConfig
portal.devMode = this.devMode
onCreate(portal)
return portal
}
Expand Down
31 changes: 29 additions & 2 deletions IonicPortals/src/main/kotlin/io/ionic/portals/PortalFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.ionic.portals

import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.pm.ApplicationInfo
import android.content.res.Configuration
import android.os.Bundle
import android.view.LayoutInflater
Expand All @@ -15,6 +16,7 @@ import io.ionic.liveupdates.LiveUpdateManager
import org.json.JSONException
import org.json.JSONObject
import java.io.File
import java.lang.reflect.Field
import kotlin.reflect.KVisibility

/**
Expand Down Expand Up @@ -282,7 +284,7 @@ open class PortalFragment : Fragment {
.setInstanceState(savedInstanceState)
.setPlugins(initialPlugins)
.addPluginInstances(initialPluginInstances)
.addWebViewListeners(webViewListeners);
.addWebViewListeners(webViewListeners)

if (portal?.liveUpdateConfig != null) {
liveUpdateFiles = LiveUpdateManager.getLatestAppDirectory(requireContext(), portal?.liveUpdateConfig?.appId!!)
Expand Down Expand Up @@ -326,6 +328,31 @@ open class PortalFragment : Fragment {
configToUse = CapConfig.Builder(requireContext()).setInitialFocus(false).create()
}

// Dev mode
val isDebuggable = 0 != requireContext().applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE
if (isDebuggable && portal?.devMode == true) {
val devConfig = DevConfiguration.getCapacitorConfig(requireContext(), portal?.name!!)
if (devConfig != null) {
configToUse = devConfig
} else {
Logger.debug("No dev config set by Portals CLI for portal ${portal?.name}, loading the non-debug config")
}

val devUrl = DevConfiguration.getServerUrl(requireContext(), portal?.name!!)
if (devUrl != null && configToUse != null) {
val devModeField: Field = configToUse.javaClass.getDeclaredField("serverUrl")
devModeField.isAccessible = true
devModeField.set(configToUse, devUrl)
} else {
val noDevUrlMsg = "No dev URL set by Portals CLI for portal ${portal?.name}"
if (devConfig != null && devConfig.serverUrl != null) {
Logger.debug("$noDevUrlMsg, using URL from dev config")
} else {
Logger.debug("$noDevUrlMsg, loading Portal from assets")
}
}
}

bridgeBuilder = bridgeBuilder.setConfig(configToUse)
bridge = bridgeBuilder.create()

Expand Down Expand Up @@ -449,4 +476,4 @@ open class PortalFragment : Fragment {
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ class PortalView : FrameLayout {
attrs?.let { attributeSet ->
portalFragment?.onInflate(context, attributeSet, null)
}

val handler = Handler()
val runnable = Runnable {
val thisView = findViewById<PortalView>(id)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ionic-portals-android",
"version": "0.8.4",
"version": "0.9.0",
"description": "Ionic Portals",
"homepage": "https://ionic.io/portals",
"author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
Expand Down

0 comments on commit 656d8bc

Please sign in to comment.