Skip to content

Commit

Permalink
Move namespace argument to extension
Browse files Browse the repository at this point in the history
  • Loading branch information
wkarl committed Jun 19, 2023
1 parent 3da4dff commit a58d365
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 38 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Evaluate JavaScript code and map values, objects and functions between Kotlin/Java and JavaScript on Android.

```kotlin
val jsBridge = JsBridge(JsBridgeConfig.bareConfig(), context, "namespace")
val jsBridge = JsBridge(JsBridgeConfig.bareConfig(), context)
val msg: String = jsBridge.evaluate("'Hello world!'.toUpperCase()")
println(msg) // HELLO WORLD!
```
Expand Down Expand Up @@ -305,15 +305,17 @@ Support for ES6 promises (Duktape: via polyfill, QuickJS: built-in). Pending job
after each evaluation.

- **LocalStorage:**<br/>
Support for browser-like local storage.
Built-in support for browser-like local storage. Use `JsBridgeConfig.standardConfig(namespace)`
to initialise the local storage extension using a namespace for separation of saved data between
multiple JsBridge instances.
_Note: If you use your own implementation of local storage you should disable this extension!

- **JS Debugger:**<br/>
JS debugger support (Duktape only via Visual Studio Code plugin)

- **JVM config:**<br/>
Offers the possibility to set a custom class loader which will be used by the JsBridge to find classes.


## Supported types

| Kotlin | Java | JS | Note
Expand Down Expand Up @@ -404,7 +406,7 @@ val nativeApi = object: NativeApi {
Bridging JavaScript and Kotlin:
```kotlin
val jsBridge = JsBridge(JsBridgeConfig.standardConfig(), context, "namespace")
val jsBridge = JsBridge(JsBridgeConfig.standardConfig("namespace"), context)
jsBridge.evaluateLocalFileUnsync(context, "js/api.js")

// JS "proxy" to native API
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public void triggerCallback(TestAidlCallback cb) throws RemoteException {
// ---

private JsBridge createAndSetUpJsBridge() {
JsBridge jsBridge = new JsBridge(JsBridgeConfig.standardConfig(), context, "test_namespace");
JsBridge jsBridge = new JsBridge(JsBridgeConfig.standardConfig("test_namespace"), context);
this.jsBridge = jsBridge;
return jsBridge;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1179,10 +1179,10 @@ class JsBridgeTest {
}

private fun stressTestHelper() {
val config = JsBridgeConfig.standardConfig().apply {
val config = JsBridgeConfig.standardConfig(NAMESPACE).apply {
xhrConfig.okHttpClient = okHttpClient
}
val subject = JsBridge(config, context, NAMESPACE)
val subject = JsBridge(config, context)

val jsExpectations = JsExpectations()
val jsExpectationsJsValue = JsValue.fromNativeObject(subject, jsExpectations)
Expand Down Expand Up @@ -1550,10 +1550,10 @@ class JsBridgeTest {
}
}

val config = JsBridgeConfig.standardConfig().apply {
val config = JsBridgeConfig.standardConfig(NAMESPACE).apply {
xhrConfig.okHttpClient = okHttpClient
}
val subject = JsBridge(config, context, NAMESPACE)
val subject = JsBridge(config, context)

val jsExpectations = JsExpectations()
val jsExpectationsJsValue = JsValue.fromNativeObject(subject, jsExpectations)
Expand Down Expand Up @@ -2593,7 +2593,7 @@ class JsBridgeTest {
messages.add(priority to message)
}
}
val subject = JsBridge(config, context, NAMESPACE)
val subject = JsBridge(config, context)
jsBridge = subject

// WHEN
Expand Down Expand Up @@ -2631,7 +2631,7 @@ class JsBridgeTest {
messages.add(priority to message)
}
}
val subject = JsBridge(config, context, NAMESPACE)
val subject = JsBridge(config, context)
jsBridge = subject

// WHEN
Expand Down Expand Up @@ -2669,7 +2669,7 @@ class JsBridgeTest {
hasMessage = true
}
}
val subject = JsBridge(config, context, NAMESPACE)
val subject = JsBridge(config, context)
jsBridge = subject

// WHEN
Expand Down Expand Up @@ -2893,7 +2893,7 @@ class JsBridgeTest {
assertTrue(errors.isEmpty())

// GIVEN
val subjectNoLocalStorage = createAndSetUpJsBridge(JsBridgeConfig.standardConfig().apply {
val subjectNoLocalStorage = createAndSetUpJsBridge(JsBridgeConfig.standardConfig(NAMESPACE).apply {
localStorageConfig.enabled = false
})

Expand All @@ -2909,7 +2909,9 @@ class JsBridgeTest {
fun testLocalStorageNamespaces() {
// GIVEN
val subject1 = createAndSetUpJsBridge()
val subject2 = createAndSetUpJsBridge(namespace = "other_namespace")
val subject2 = createAndSetUpJsBridge(config = JsBridgeConfig.standardConfig("other_namespace").apply {
xhrConfig.okHttpClient = okHttpClient
},)

// WHEN
subject1.evaluateBlocking<Unit>("""localStorage.setItem("key", "value");""")
Expand Down Expand Up @@ -2968,13 +2970,12 @@ class JsBridgeTest {
// ---

private fun createAndSetUpJsBridge(
config: JsBridgeConfig = JsBridgeConfig.standardConfig().apply {
config: JsBridgeConfig = JsBridgeConfig.standardConfig(NAMESPACE).apply {
xhrConfig.okHttpClient = okHttpClient
},
namespace: String = NAMESPACE,
): JsBridge {

return JsBridge(config, context, namespace).also { jsBridge ->
return JsBridge(config, context).also { jsBridge ->
this@JsBridgeTest.jsBridge = jsBridge

jsBridge.registerErrorListener(createErrorListener())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class ReadmeTest {

@Before
fun setUp() {
jsBridge = JsBridge(JsBridgeConfig.standardConfig(), context,"test_namespace")
jsBridge = JsBridge(JsBridgeConfig.standardConfig("test_namespace"), context)
}

@After
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,10 @@ import java.lang.reflect.Proxy
* to be performed sequentially (via an internal queue).
*
* @param config JsBridge configuration
* @param context Context needed for built in implementation of local storage
* @param namespace arbitrary string for separation of local storage between multiple JsBridge instances
* @param context Context needed for local storage extension
*/
class JsBridge
constructor(config: JsBridgeConfig, context: Context, namespace: String) : CoroutineScope {
constructor(config: JsBridgeConfig, context: Context) : CoroutineScope {

companion object {
private var isLibraryLoaded = false
Expand Down Expand Up @@ -162,7 +161,7 @@ class JsBridge
if (config.xhrConfig.enabled)
xhrExtension = XMLHttpRequestExtension(this@JsBridge, config.xhrConfig)
if (config.localStorageConfig.enabled)
localStorageExtension = LocalStorageExtension(this@JsBridge, config.localStorageConfig, context.applicationContext, namespace)
localStorageExtension = LocalStorageExtension(this@JsBridge, config.localStorageConfig, context.applicationContext)
config.jvmConfig.customClassLoader?.let { customClassLoader = it }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,28 @@ import okhttp3.OkHttpClient
class JsBridgeConfig
private constructor() {
companion object {
/**
* Creates an instance of JsBridgeConfig without any extensions.
*/
@JvmStatic
fun bareConfig() = JsBridgeConfig()

/**
* Creates an instance of JsBridgeConfig and enables all extensions.
* @param localStorageNamespace arbitrary string for separation of local storage between
* multiple JsBridge instances. If you use the same namespace for multiple instances of
* JsBridge there might be collisions if identical keys are used to store values.
*/
@JvmStatic
fun standardConfig() = JsBridgeConfig().apply {
fun standardConfig(localStorageNamespace: String) = JsBridgeConfig().apply {
setTimeoutConfig.enabled = true
xhrConfig.enabled = true
promiseConfig.enabled = true
consoleConfig.enabled = true
localStorageConfig.enabled = true
localStorageConfig.apply {
enabled = true
namespace = localStorageNamespace
}
}
}

Expand Down Expand Up @@ -62,15 +74,7 @@ private constructor() {
class LocalStorageConfig {
var enabled: Boolean = false

/**
* Only disable namespaces if a particular instance of JsBridge requires access to local
* storage key/value pairs that were saved with a previous version of the library.
*
* You should try to avoid using multiple unrelated instances of JsBridge without namespaces
* or with an identical namespace. An exception would be if you want to explicitly share data
* between instances and the possibility of key name collisions is not an issue.
*/
var useNamespaces: Boolean = true
var namespace: String = ""
}

class JvmConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ interface LocalStorageInteface : JsToNativeInterface {
fun clear()
}

class LocalStorage(context: Context, namespace: String?) : LocalStorageInteface {
class LocalStorage(context: Context, namespace: String) : LocalStorageInteface {

private val localStoragePreferences = context.getSharedPreferences(
namespace?.let { "${it.takeIf { it.isNotEmpty() } ?: "default"}.LOCAL_STORAGE_PREFERENCES" }
?: "${context.applicationInfo.packageName}.LOCAL_STORAGE_PREFERENCE_FILE_KEY",
"${namespace.takeIf { it.isNotEmpty() } ?: "default"}.LOCAL_STORAGE_PREFERENCES",
Context.MODE_PRIVATE
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ internal class LocalStorageExtension(
jsBridge: JsBridge,
config: JsBridgeConfig.LocalStorageConfig,
context: Context,
namespace: String,
) {

init {
val localStorage: LocalStorageInteface = LocalStorage(context, namespace.takeIf { config.useNamespaces })
val localStorage: LocalStorageInteface = LocalStorage(context, config.namespace)
val localStorageJsValue = JsValue.fromNativeObject(jsBridge, localStorage)
localStorageJsValue.assignToGlobal("localStorage")
}
Expand Down

0 comments on commit a58d365

Please sign in to comment.