Skip to content

Commit

Permalink
Wrap up
Browse files Browse the repository at this point in the history
  • Loading branch information
crow committed Oct 19, 2024
1 parent 8fa3a69 commit ac2cd52
Show file tree
Hide file tree
Showing 19 changed files with 1,083 additions and 90 deletions.
149 changes: 146 additions & 3 deletions android/src/main/kotlin/com/airship/flutter/AirshipPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package com.airship.flutter
import android.app.Activity
import android.content.Context
import android.os.Build
import android.util.Log
import com.urbanairship.actions.ActionResult
import com.urbanairship.android.framework.proxy.Event
import com.urbanairship.android.framework.proxy.EventType
import com.urbanairship.android.framework.proxy.events.EventEmitter
import com.urbanairship.android.framework.proxy.proxies.AirshipProxy
import com.urbanairship.android.framework.proxy.proxies.FeatureFlagProxy
import com.urbanairship.android.framework.proxy.proxies.LiveUpdateRequest
import com.urbanairship.android.framework.proxy.proxies.EnableUserNotificationsArgs
import com.urbanairship.json.JsonValue
import com.urbanairship.json.toJsonList
import io.flutter.embedding.engine.FlutterShellArgs
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
Expand All @@ -25,6 +28,8 @@ import io.flutter.plugin.platform.PlatformViewRegistry
import kotlinx.coroutines.*
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
import kotlinx.coroutines.Dispatchers


class AirshipPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

Expand Down Expand Up @@ -109,6 +114,7 @@ class AirshipPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

override fun onMethodCall(call: MethodCall, result: Result) {
val proxy = AirshipProxy.shared(context)
val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())

when (call.method) {
// Flutter
Expand Down Expand Up @@ -153,9 +159,31 @@ class AirshipPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

// Push
"push#setUserNotificationsEnabled" -> result.resolveResult(call) { proxy.push.setUserNotificationsEnabled(call.booleanArg()) }
"push#enableUserNotifications" -> result.resolvePending(call) { proxy.push.enableUserPushNotifications() }
"push#enableUserNotifications" -> {
val arg = call.arguments as? String
val enableArgs = arg?.let {
try {
EnableUserNotificationsArgs.fromJson(JsonValue.parseString(it))
} catch (e: Exception) {
null
}
}

coroutineScope.launch {
try {
val enableResult = proxy.push.enableUserPushNotifications(enableArgs)
result.success(enableResult)
} catch (e: Exception) {
result.error("ERROR", "Failed to enable user notifications", e.localizedMessage)
}
}
}
"push#isUserNotificationsEnabled" -> result.resolveResult(call) { proxy.push.isUserNotificationsEnabled() }
"push#getNotificationStatus" -> result.resolveResult(call) { proxy.push.getNotificationStatus() }
"push#getNotificationStatus" -> result.resolveResult(call) {
coroutineScope.launch {
proxy.push.getNotificationStatus()
}
}
"push#getActiveNotifications" -> result.resolveResult(call) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
proxy.push.getActiveNotifications()
Expand Down Expand Up @@ -248,6 +276,121 @@ class AirshipPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}
}
}
// Live Activities

"featureFlagManager#trackInteraction" -> {
result.resolveDeferred(call) { callback ->
scope.launch {
try {
val args = call.jsonArgs()

val wrapped = JsonValue.wrap(args)
val featureFlagProxy = FeatureFlagProxy(wrapped)
proxy.featureFlagManager.trackInteraction(flag = featureFlagProxy)
callback(null, null)
} catch (e: Exception) {
callback(null, e)
}
}
}
}

"liveUpdate#start" -> result.resolveResult(call) {
try {
val args = call.jsonArgs()
Log.d("AirshipPlugin", "Received args for liveUpdate#start: $args")

val startRequest = LiveUpdateRequest.Start.fromJson(args)

Log.d("AirshipPlugin", "Created LiveUpdateRequest.Start: $startRequest")

proxy.liveUpdateManager.start(startRequest)
Log.d("AirshipPlugin", "LiveUpdate start method called successfully")

null // Return null as the start function doesn't return anything
} catch (e: Exception) {
throw e
}
}

"liveUpdate#update" -> result.resolveResult(call) {
try {
val args = call.jsonArgs()
Log.d("AirshipPlugin", "Received args for liveUpdate#update: $args")

val updateRequest = LiveUpdateRequest.Update.fromJson(args)

proxy.liveUpdateManager.update(updateRequest)
Log.d("AirshipPlugin", "LiveUpdate update method called successfully")
null
} catch (e: Exception) {
Log.e("AirshipPlugin", "Error processing liveUpdate#update request", e)
throw e
}
}

"liveUpdate#list" -> result.resolveDeferred(call) { callback ->
try {
val args = call.jsonArgs()
Log.d("AirshipPlugin", "Received args for liveUpdate#list: $args")

val listRequest = LiveUpdateRequest.List.fromJson(args)

coroutineScope.launch {
try {
val liveUpdates = proxy.liveUpdateManager.list(listRequest)
Log.d("AirshipPlugin", "LiveUpdate list method completed successfully")
callback(liveUpdates.toJsonList(), null)
} catch (e: Exception) {
Log.e("AirshipPlugin", "Error listing LiveUpdates", e)
callback(null, e)
}
}
} catch (e: Exception) {
Log.e("AirshipPlugin", "Error processing liveUpdate#list request", e)
callback(null, e)
}
}

"liveUpdate#listAll" -> result.resolveDeferred(call) { callback ->
coroutineScope.launch {
try {
val liveUpdates = proxy.liveUpdateManager.listAll()
Log.d("AirshipPlugin", "LiveUpdate listAll method completed successfully")
callback(JsonValue.wrap(liveUpdates), null)
} catch (e: Exception) {
Log.e("AirshipPlugin", "Error listing all LiveUpdates", e)
callback(null, e)
}
}
}

"liveUpdate#end" -> result.resolveResult(call) {
try {
val args = call.jsonArgs()
Log.d("AirshipPlugin", "Received args for liveUpdate#end: $args")

val endRequest = LiveUpdateRequest.End.fromJson(args)

proxy.liveUpdateManager.end(endRequest)
Log.d("AirshipPlugin", "LiveUpdate end method called successfully")
null
} catch (e: Exception) {
Log.e("AirshipPlugin", "Error processing liveUpdate#end request", e)
throw e
}
}

"liveUpdate#clearAll" -> result.resolveResult(call) {
try {
proxy.liveUpdateManager.clearAll()
Log.d("AirshipPlugin", "LiveUpdate clearAll method called successfully")
null
} catch (e: Exception) {
Log.e("AirshipPlugin", "Error processing liveUpdate#clearAll request", e)
throw e
}
}

// Feature Flag
"featureFlagManager#flag" -> result.resolveDeferred(call) { callback ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* Copyright Urban Airship and Contributors */

package com.urbanairship.reactnative

import android.content.Context
import com.urbanairship.UAirship

/**
* Extender that will be called during takeOff to customize the airship instance.
* Register the extender fully qualified class name in the manifest under the key
* `com.urbanairship.flutter.AIRSHIP_EXTENDER`.
*/
@Deprecated("Use com.urbanairship.android.framework.proxy.AirshipPluginExtender instead and register it under the manifest key `com.urbanairship.plugin.extender`")
interface AirshipExtender {
fun onAirshipReady(context: Context, airship: UAirship)
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ class FlutterAutopilot : BaseAutopilot() {
private val appContext: Context
get() = UAirship.getApplicationContext()

override fun onAirshipReady(airship: UAirship) {
super.onAirshipReady(airship)

override fun onReady(context: Context, airship: UAirship) {
Log.i("FlutterAutopilot", "onAirshipReady")

// If running in the background, start the background Isolate
Expand Down
5 changes: 5 additions & 0 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
<application
android:label="airship_example"
android:icon="@mipmap/ic_launcher">

<meta-data
android:name="com.urbanairship.plugin.extender"
android:value="com.urbanairship.sample.AirshipExtender" />

<activity
android:name="io.flutter.embedding.android.FlutterActivity"
android:launchMode="singleTop"
Expand Down
69 changes: 69 additions & 0 deletions example/android/app/src/main/java/com/AirshipExtender.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.urbanairship.sample

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.annotation.Keep
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.urbanairship.UAirship
import com.urbanairship.android.framework.proxy.AirshipPluginExtender
import com.urbanairship.json.requireField
import com.urbanairship.liveupdate.LiveUpdate
import com.urbanairship.liveupdate.LiveUpdateEvent
import com.urbanairship.liveupdate.LiveUpdateManager
import com.urbanairship.liveupdate.LiveUpdateResult
import com.urbanairship.liveupdate.SuspendLiveUpdateNotificationHandler


@Keep
public final class AirshipExtender: AirshipPluginExtender {
override fun onAirshipReady(context: Context, airship: UAirship) {
LiveUpdateManager.shared().register("Example", ExampleLiveUpdateHandler())
}
}

public final class ExampleLiveUpdateHandler: SuspendLiveUpdateNotificationHandler() {
override suspend fun onUpdate(
context: Context,
event: LiveUpdateEvent,
update: LiveUpdate
): LiveUpdateResult<NotificationCompat.Builder> {

if (event == LiveUpdateEvent.END) {
// Dismiss the live update on END. The default behavior will leave the Live Update
// in the notification tray until the dismissal time is reached or the user dismisses it.
return LiveUpdateResult.cancel()
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel("emoji-example", "Emoji example", importance)
channel.description = "Emoji example"
NotificationManagerCompat.from(context).createNotificationChannel(channel)
}

val launchIntent = context.packageManager
.getLaunchIntentForPackage(context.packageName)
?.addCategory(update.name)
?.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
?.setPackage(null)

val contentIntent = PendingIntent.getActivity(
context, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE
)

val notification = NotificationCompat.Builder(context, "emoji-example")
.setSmallIcon(R.drawable.ic_notification)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_EVENT)
.setContentTitle("Example Live Update")
.setContentText(update.content.requireField<String>("emoji"))
.setContentIntent(contentIntent)

return LiveUpdateResult.ok(notification)
}
}
4 changes: 4 additions & 0 deletions example/android/app/src/main/res/drawable/ic_notification.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

</selector>
4 changes: 4 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ void main() {
]);

var config = AirshipConfig(
androidConfig: AndroidConfig(
notificationConfig: AndroidNotificationConfig(
icon: "ic_notification",
)),
defaultEnvironment: ConfigEnvironment(
appKey: "APP_KEY",
appSecret: "APP_SECRET",
Expand Down
Loading

0 comments on commit ac2cd52

Please sign in to comment.