Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
#
.DS_Store

# XDE
.expo/

# VSCode
.vscode/
jsconfig.json
Expand Down Expand Up @@ -43,9 +40,15 @@ android.iml
# Cocoapods
#
example/ios/Pods
example-0.73/ios/Pods
example-0.79/ios/Pods
example-0.83/ios/Pods

# Ruby
example/vendor/
example-0.73/vendor/
example-0.79/vendor/
example-0.83/vendor/

# node.js
#
Expand All @@ -70,3 +73,10 @@ android/keystores/debug.keystore
lib/
.yarn/install-state.gz
example/.yarn/install-state.gz
example-0.73/.yarn/install-state.gz
example-0.79/.yarn/install-state.gz
example-0.83/.yarn/install-state.gz

google-services.json


56 changes: 40 additions & 16 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,32 +1,46 @@
buildscript {
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["RNMovableInk_kotlinVersion"]

repositories {
google()
mavenCentral()
maven {
url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
url 'https://central.sonatype.com/repository/maven-snapshots/'
}
}

dependencies {
classpath "com.android.tools.build:gradle:7.2.2"
// noinspection DifferentKotlinGradleVersion
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// AGP and Kotlin versions provided by the consuming app
}
}

def isNewArchitectureEnabled() {
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
}

/**
* Get a property value with fallback logic:
* 1. First tries rootProject.ext (set by consuming app)
* 2. Falls back to RNMovableInk_ prefixed property (library-specific)
* 3. Falls back to RN prefixed property (common React Native pattern)
*/
def getExtOrDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["RN" + name]
if (rootProject.ext.has(name)) {
return rootProject.ext.get(name)
}
// Try RNMovableInk_ prefix first (library-specific), then RN prefix (common pattern)
return project.properties["RNMovableInk_" + name] ?: project.properties["RN" + name]
}

/**
* Get an integer property value with fallback logic.
* Same fallback order as getExtOrDefault, but converts to Integer.
*/
def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RN" + name]).toInteger()
if (rootProject.ext.has(name)) {
return rootProject.ext.get(name)
}
// Try RNMovableInk_ prefix first (library-specific), then RN prefix (common pattern)
def value = project.properties["RNMovableInk_" + name] ?: project.properties["RN" + name]
return value.toInteger()
}

def supportsNamespace() {
Expand All @@ -40,7 +54,6 @@ def supportsNamespace() {

apply plugin: "com.android.library"
apply plugin: "kotlin-android"
apply plugin: 'org.jetbrains.kotlin.android'

if (isNewArchitectureEnabled()) {
apply plugin: "com.facebook.react"
Expand Down Expand Up @@ -70,22 +83,34 @@ android {
}
}

lintOptions {
lint {
disable "GradleCompatible"
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = "17"
//freeCompilerArgs += ["-Xskip-metadata-version-check"]
}

}

// Configure all Kotlin compile tasks to skip metadata version check
// tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
// kotlinOptions {
// freeCompilerArgs += ["-Xskip-metadata-version-check"]
// }
// }

repositories {
mavenCentral()
google()
maven {
url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
url 'https://central.sonatype.com/repository/maven-snapshots/'
}
}

Expand All @@ -97,9 +122,8 @@ dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.movableink.sdk:inked:2.2.0"
implementation "com.movableink.sdk:inked:2.3.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.7.0"

}

if (isNewArchitectureEnabled()) {
Expand Down
6 changes: 3 additions & 3 deletions android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
RNMovableInk_kotlinVersion=1.8.0
RNMovableInk_kotlinVersion=2.2.0
RNMovableInk_minSdkVersion=24
RNMovableInk_targetSdkVersion=33
RNMovableInk_compileSdkVersion=33
RNMovableInk_targetSdkVersion=34
RNMovableInk_compileSdkVersion=34
RNMovableInk_ndkversion=23.1.7779620
android.useAndroidX=true
56 changes: 36 additions & 20 deletions android/src/main/java/com/rnmovableink/RNMovableInkModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.movableink.inked.inAppMessage.MovableInAppClient
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import android.util.Log

class RNMovableInkModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
Expand Down Expand Up @@ -85,41 +86,56 @@ class RNMovableInkModule(reactContext: ReactApplicationContext) :
}
}

@ReactMethod
fun showInAppMessage(url: String, callback: Callback) {
val activity = currentActivity
if (activity is androidx.lifecycle.LifecycleOwner) {
activity.lifecycleScope.launch {
try {
MIClient.showInAppBrowser(
activity,
url,
listener = object : MovableInAppClient.OnUrlLoadingListener {
override fun onButtonClicked(value: String) {
activity.runOnUiThread {
callback.invoke(value)
}
@ReactMethod
fun showInAppMessage(url: String, callback: Callback) {
val activity = reactApplicationContext.currentActivity
if (activity == null) {
Log.d("MISDK", "No current activity")
callback.invoke("Error: No current activity")
return
}
if (activity !is androidx.lifecycle.LifecycleOwner) {
Log.d("MISDK", "Activity is not a LifecycleOwner")
callback.invoke("Error: Activity is not a LifecycleOwner")
return
}
Comment on lines +89 to +101
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

showInAppMessage now invokes the callback with strings like "Error: ..." when there is no activity / wrong activity type. The JS/TS contract treats the callback argument as a button ID, so passing error strings can make failures look like successful button taps. Consider surfacing failures via a separate error path (e.g., Promise reject, event, or a distinct error callback) and keep this callback reserved for actual button IDs.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is inline with how the method already handles an exception, it invokes an string with "Error".

activity.lifecycleScope.launch {
try {
MIClient.showInAppBrowser(
activity,
url,
listener = object : MovableInAppClient.OnUrlLoadingListener {
override fun onButtonClicked(value: String) {
(activity as? android.app.Activity)?.runOnUiThread {
callback.invoke(value)
}
}
)
} catch (e: Exception) {
activity.runOnUiThread {
callback.invoke("Error: ${e.message}")
}
)
} catch (e: Exception) {
(activity as? android.app.Activity)?.runOnUiThread {
Log.e("MISDK", "Error showing in-app message", e)
callback.invoke("Error: ${e.message}")
}
}
}
}
}

@ReactMethod
fun setValidPasteboardValues(values: ReadableArray) {
MIClient.validPasteboardValues(values.toStringList())
}

@ReactMethod
fun handlePushNotificationOpenedWithContent(properties: ReadableMap) {
// val map: Map<String, String> = properties.toHashMap().mapValues { it.value.toString() }
// MIClient.handlePushNotificationOpened(map)
Comment on lines +131 to +132
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handlePushNotificationOpenedWithContent is annotated with @ReactMethod but the body is commented out, so notifications opened in the example apps won’t be forwarded to the MovableInk SDK. Please convert the ReadableMap into the structure expected by MIClient.handlePushNotificationOpened(...) and invoke it (or remove the JS API until implemented).

Suggested change
// val map: Map<String, String> = properties.toHashMap().mapValues { it.value.toString() }
// MIClient.handlePushNotificationOpened(map)
val map: Map<String, String> = properties.toHashMap().mapValues { it.value.toString() }
MIClient.handlePushNotificationOpened(map)

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be enabled when we go to release this - since the only build that has this is a snapshot.

}

fun ReadableArray.toStringList(): List<String> {
val stringList = mutableListOf<String>()
for (i in 0 until size()) {
stringList.add(getString(i))
getString(i)?.let { stringList.add(it) }
}
return stringList
}
Expand Down
File renamed without changes.
4 changes: 4 additions & 0 deletions example-0.79/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: '@react-native',
};
75 changes: 75 additions & 0 deletions example-0.79/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
**/.xcode.env.local

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof
.cxx/
*.keystore
!debug.keystore
.kotlin/

# node.js
#
node_modules/
npm-debug.log
yarn-error.log

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/

**/fastlane/report.xml
**/fastlane/Preview.html
**/fastlane/screenshots
**/fastlane/test_output

# Bundle artifact
*.jsbundle

# Ruby / CocoaPods
**/Pods/
/vendor/bundle/

# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*

# testing
/coverage

# Yarn
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
7 changes: 7 additions & 0 deletions example-0.79/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
arrowParens: 'avoid',
bracketSameLine: true,
bracketSpacing: false,
singleQuote: true,
trailingComma: 'all',
};
1 change: 1 addition & 0 deletions example-0.79/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions example/.yarnrc.yml → example-0.79/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
yarnPath: .yarn/releases/yarn-4.5.1.cjs
enableGlobalCache: false
17 changes: 17 additions & 0 deletions example-0.79/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
source 'https://rubygems.org'

# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby ">= 2.6.10"

# Exclude problematic versions of cocoapods and activesupport that causes build failures.
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
gem 'xcodeproj', '< 1.26.0'
gem 'CFPropertyList', '= 3.0.7'
gem 'concurrent-ruby', '< 1.3.4'

# Ruby 3.4.0 has removed some libraries from the standard library.
gem 'bigdecimal'
gem 'logger'
gem 'benchmark'
gem 'mutex_m'
Loading