Skip to content

Commit 656d8bc

Browse files
authored
feat: support the portals CLI functionality for android serve (#65)
1 parent d0253eb commit 656d8bc

File tree

5 files changed

+119
-4
lines changed

5 files changed

+119
-4
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package io.ionic.portals
2+
3+
import android.content.Context
4+
import com.getcapacitor.CapConfig
5+
6+
/**
7+
* This class is used to load the server URL and Capacitor configuration from the assets folder when the app
8+
* is being run in developer mode with the Portals CLI.
9+
*/
10+
object DevConfiguration {
11+
12+
/**
13+
* Get the server URL for the given portal name from the developer mode assets folder.
14+
*/
15+
fun getServerUrl(context: Context, portalName: String): String? {
16+
val portalDirName = "$portalName.debug"
17+
val generalDirName = "portal.debug"
18+
val urlFileName = "url"
19+
20+
val assetManager = context.assets
21+
var serverUrl = try {
22+
assetManager.open("$portalDirName/$urlFileName").bufferedReader().use {
23+
it.readText()
24+
}
25+
} catch (e: Exception) {
26+
null
27+
}
28+
29+
if (serverUrl == null) {
30+
serverUrl = try {
31+
assetManager.open("$generalDirName/$urlFileName").bufferedReader().use {
32+
it.readText()
33+
}
34+
} catch (e: Exception) {
35+
null
36+
}
37+
}
38+
39+
return serverUrl
40+
}
41+
42+
/**
43+
* Get the Capacitor configuration for the given portal name from the developer mode assets folder.
44+
*/
45+
fun getCapacitorConfig(context: Context, portalName: String): CapConfig? {
46+
val portalDirName = "$portalName.debug"
47+
val generalDirName = "portal.debug"
48+
val capConfigFileName = "capacitor.config.json"
49+
50+
var serverConfig = try {
51+
val configFile = context.assets.open("$portalDirName/$capConfigFileName")
52+
CapConfig.loadFromAssets(context, portalDirName)
53+
} catch (e: Exception) {
54+
null
55+
}
56+
57+
if (serverConfig == null) {
58+
serverConfig = try {
59+
val configFile = context.assets.open("$generalDirName/$capConfigFileName")
60+
CapConfig.loadFromAssets(context, generalDirName)
61+
} catch (e: Exception) {
62+
null
63+
}
64+
}
65+
66+
return serverConfig
67+
}
68+
}

IonicPortals/src/main/kotlin/io/ionic/portals/Portal.kt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class Portal(val name: String) {
6767
var startDir: String = ""
6868
get() = if (field.isEmpty()) name else field
6969

70+
/**
71+
* If the Portal should be loaded in development mode and look for a server URL.
72+
*/
73+
var devMode: Boolean = true
74+
7075
/**
7176
* A LiveUpdate config, if live updates is being used.
7277
*/
@@ -304,9 +309,10 @@ class PortalBuilder(val name: String) {
304309
private var portalFragmentType: Class<out PortalFragment?> = PortalFragment::class.java
305310
private var onCreate: (portal: Portal) -> Unit = {}
306311
private var liveUpdateConfig: LiveUpdate? = null
312+
private var devMode: Boolean = true
307313

308314
internal constructor(name: String, onCreate: (portal: Portal) -> Unit) : this(name) {
309-
this.onCreate = onCreate;
315+
this.onCreate = onCreate
310316
}
311317

312318
/**
@@ -555,6 +561,18 @@ class PortalBuilder(val name: String) {
555561
return this
556562
}
557563

564+
/**
565+
* Set development mode on the Portal which will look for a server URL set by the Portals CLI.
566+
* This is set to true by default but can be turned off manually if desired.
567+
*
568+
* @param devMode if the Portal should be loaded in development mode
569+
* @return the instance of the PortalBuilder with the development mode set
570+
*/
571+
fun setDevMode(devMode: Boolean): PortalBuilder {
572+
this.devMode = devMode
573+
return this
574+
}
575+
558576
/**
559577
* Creates the [Portal] instance from the current state of the [PortalBuilder] provided.
560578
* This finishes building the Portal.
@@ -580,6 +598,7 @@ class PortalBuilder(val name: String) {
580598
portal.initialContext = this.initialContext
581599
portal.portalFragmentType = this.portalFragmentType
582600
portal.liveUpdateConfig = this.liveUpdateConfig
601+
portal.devMode = this.devMode
583602
onCreate(portal)
584603
return portal
585604
}

IonicPortals/src/main/kotlin/io/ionic/portals/PortalFragment.kt

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package io.ionic.portals
22

33
import android.annotation.SuppressLint
44
import android.app.AlertDialog
5+
import android.content.pm.ApplicationInfo
56
import android.content.res.Configuration
67
import android.os.Bundle
78
import android.view.LayoutInflater
@@ -15,6 +16,7 @@ import io.ionic.liveupdates.LiveUpdateManager
1516
import org.json.JSONException
1617
import org.json.JSONObject
1718
import java.io.File
19+
import java.lang.reflect.Field
1820
import kotlin.reflect.KVisibility
1921

2022
/**
@@ -282,7 +284,7 @@ open class PortalFragment : Fragment {
282284
.setInstanceState(savedInstanceState)
283285
.setPlugins(initialPlugins)
284286
.addPluginInstances(initialPluginInstances)
285-
.addWebViewListeners(webViewListeners);
287+
.addWebViewListeners(webViewListeners)
286288

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

331+
// Dev mode
332+
val isDebuggable = 0 != requireContext().applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE
333+
if (isDebuggable && portal?.devMode == true) {
334+
val devConfig = DevConfiguration.getCapacitorConfig(requireContext(), portal?.name!!)
335+
if (devConfig != null) {
336+
configToUse = devConfig
337+
} else {
338+
Logger.debug("No dev config set by Portals CLI for portal ${portal?.name}, loading the non-debug config")
339+
}
340+
341+
val devUrl = DevConfiguration.getServerUrl(requireContext(), portal?.name!!)
342+
if (devUrl != null && configToUse != null) {
343+
val devModeField: Field = configToUse.javaClass.getDeclaredField("serverUrl")
344+
devModeField.isAccessible = true
345+
devModeField.set(configToUse, devUrl)
346+
} else {
347+
val noDevUrlMsg = "No dev URL set by Portals CLI for portal ${portal?.name}"
348+
if (devConfig != null && devConfig.serverUrl != null) {
349+
Logger.debug("$noDevUrlMsg, using URL from dev config")
350+
} else {
351+
Logger.debug("$noDevUrlMsg, loading Portal from assets")
352+
}
353+
}
354+
}
355+
329356
bridgeBuilder = bridgeBuilder.setConfig(configToUse)
330357
bridge = bridgeBuilder.create()
331358

@@ -449,4 +476,4 @@ open class PortalFragment : Fragment {
449476
}
450477
}
451478
}
452-
}
479+
}

IonicPortals/src/main/kotlin/io/ionic/portals/PortalView.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ class PortalView : FrameLayout {
192192
attrs?.let { attributeSet ->
193193
portalFragment?.onInflate(context, attributeSet, null)
194194
}
195+
195196
val handler = Handler()
196197
val runnable = Runnable {
197198
val thisView = findViewById<PortalView>(id)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ionic-portals-android",
3-
"version": "0.8.4",
3+
"version": "0.9.0",
44
"description": "Ionic Portals",
55
"homepage": "https://ionic.io/portals",
66
"author": "Ionic Team <[email protected]> (https://ionic.io)",

0 commit comments

Comments
 (0)