Skip to content

Commit 96499da

Browse files
authored
Embedded (#576)
* Embedded * Docs * Remove debug logs * Feedback
1 parent 75f68af commit 96499da

26 files changed

+553
-30
lines changed

android/gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ Airship_minSdkVersion=21
33
Airship_targetSdkVersion=34
44
Airship_compileSdkVersion=34
55
Airship_ndkversion=26.1.10909125
6-
Airship_airshipProxyVersion=7.1.2
6+
Airship_airshipProxyVersion=7.3.0

android/src/main/java/com/urbanairship/reactnative/AirshipModule.kt

+5
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,11 @@ class AirshipModule internal constructor(val context: ReactApplicationContext) :
546546
}
547547
}
548548

549+
@ReactMethod
550+
override fun inAppResendPendingEmbeddedEvent() {
551+
proxy.inApp.resendLastEmbeddedEvent()
552+
}
553+
549554
@ReactMethod
550555
override fun messageCenterGetUnreadCount(promise: Promise) {
551556
promise.resolveResult {

android/src/main/java/com/urbanairship/reactnative/AirshipPackage.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ class AirshipPackage : TurboReactPackage() {
3636

3737

3838
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
39-
return listOf<ViewManager<*, *>>(ReactMessageViewManager())
39+
return listOf<ViewManager<*, *>>(ReactMessageViewManager(), ReactEmbeddedViewManager())
4040
}
4141
}

android/src/main/java/com/urbanairship/reactnative/ReactAutopilot.kt

+21-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ import android.content.pm.PackageManager
88
import com.urbanairship.UAirship
99
import com.urbanairship.analytics.Extension
1010
import com.urbanairship.android.framework.proxy.BaseAutopilot
11+
import com.urbanairship.android.framework.proxy.Event
12+
import com.urbanairship.android.framework.proxy.EventType
1113
import com.urbanairship.android.framework.proxy.ProxyLogger
1214
import com.urbanairship.android.framework.proxy.ProxyStore
1315
import com.urbanairship.android.framework.proxy.events.EventEmitter
16+
import com.urbanairship.embedded.AirshipEmbeddedInfo
17+
import com.urbanairship.embedded.AirshipEmbeddedObserver
18+
import com.urbanairship.json.JsonMap
19+
import com.urbanairship.json.jsonMapOf
1420
import kotlinx.coroutines.MainScope
1521
import kotlinx.coroutines.flow.filter
1622
import kotlinx.coroutines.launch
@@ -35,7 +41,13 @@ class ReactAutopilot : BaseAutopilot() {
3541
}
3642
}
3743

38-
// Set our custom notification provider
44+
MainScope().launch {
45+
AirshipEmbeddedObserver(filter = { true }).embeddedViewInfoFlow.collect {
46+
EventEmitter.shared().addEvent(PendingEmbeddedUpdated(it))
47+
}
48+
}
49+
50+
// Set our custom notification providerr
3951
val notificationProvider = ReactNotificationProvider(context, airship.airshipConfigOptions)
4052
airship.pushManager.notificationProvider = notificationProvider
4153

@@ -75,4 +87,12 @@ class ReactAutopilot : BaseAutopilot() {
7587
companion object {
7688
const val EXTENDER_MANIFEST_KEY = "com.urbanairship.reactnative.AIRSHIP_EXTENDER"
7789
}
90+
}
91+
92+
internal class PendingEmbeddedUpdated(pending: List<AirshipEmbeddedInfo>) : Event {
93+
override val type = EventType.PENDING_EMBEDDED_UPDATED
94+
95+
override val body: JsonMap = jsonMapOf(
96+
"pending" to pending.map { jsonMapOf( "embeddedId" to it.embeddedId ) }
97+
)
7898
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* Copyright Airship and Contributors */
2+
3+
package com.urbanairship.reactnative
4+
5+
import android.content.Context
6+
import android.graphics.Color
7+
import android.view.View
8+
import android.widget.FrameLayout
9+
import androidx.core.view.doOnAttach
10+
import com.facebook.react.bridge.LifecycleEventListener
11+
import com.urbanairship.embedded.AirshipEmbeddedView
12+
13+
class ReactEmbeddedView(context: Context) : FrameLayout(context) {
14+
15+
private var embeddedId: String? = null
16+
17+
fun load(embeddedId: String) {
18+
if (this.embeddedId == embeddedId) {
19+
return
20+
}
21+
22+
removeAllViews()
23+
this.embeddedId = embeddedId
24+
addView(AirshipEmbeddedView(context, embeddedId))
25+
}
26+
27+
override fun requestLayout() {
28+
super.requestLayout()
29+
30+
// This view relies on a measure + layout pass happening after it calls requestLayout().
31+
// https://github.com/facebook/react-native/issues/4990#issuecomment-180415510
32+
// https://stackoverflow.com/questions/39836356/react-native-resize-custom-ui-component
33+
post(measureAndLayout)
34+
}
35+
36+
private val measureAndLayout = Runnable {
37+
measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
38+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY))
39+
layout(left, top, right, bottom)
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* Copyright Airship and Contributors */
2+
3+
package com.urbanairship.reactnative
4+
5+
import com.facebook.react.uimanager.SimpleViewManager
6+
import com.facebook.react.uimanager.ThemedReactContext
7+
import com.facebook.react.uimanager.ViewManagerDelegate
8+
import com.facebook.react.uimanager.annotations.ReactProp
9+
import com.facebook.react.viewmanagers.RTNAirshipEmbeddedViewManagerDelegate
10+
import com.facebook.react.viewmanagers.RTNAirshipEmbeddedViewManagerInterface
11+
12+
13+
class ReactEmbeddedViewManager : SimpleViewManager<ReactEmbeddedView>(),
14+
RTNAirshipEmbeddedViewManagerInterface<ReactEmbeddedView> {
15+
16+
private val delegate = RTNAirshipEmbeddedViewManagerDelegate(this)
17+
18+
override fun getName(): String {
19+
return REACT_CLASS
20+
}
21+
22+
override fun getDelegate(): ViewManagerDelegate<ReactEmbeddedView?> {
23+
return delegate
24+
}
25+
26+
override fun createViewInstance(reactContext: ThemedReactContext): ReactEmbeddedView {
27+
return ReactEmbeddedView(reactContext)
28+
}
29+
30+
@ReactProp(name = "embeddedId")
31+
override fun setEmbeddedId(view: ReactEmbeddedView, embeddedId: String?) {
32+
embeddedId?.let {
33+
view.load(it)
34+
}
35+
}
36+
37+
38+
companion object {
39+
const val REACT_CLASS = "RTNAirshipEmbeddedView"
40+
}
41+
}

android/src/main/java/com/urbanairship/reactnative/Utils.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ object Utils {
2727
EventType.FOREGROUND_PUSH_RECEIVED,
2828
EventType.BACKGROUND_PUSH_RECEIVED
2929
),
30-
"com.airship.notification_status_changed" to listOf(EventType.NOTIFICATION_STATUS_CHANGED)
30+
"com.airship.notification_status_changed" to listOf(EventType.NOTIFICATION_STATUS_CHANGED),
31+
"com.airship.pending_embedded_updated" to listOf(EventType.PENDING_EMBEDDED_UPDATED)
3132
)
3233

3334
fun convertArray(array: ReadableArray?): JsonValue {

android/src/oldarch/java/com/urbanairship/reactnative/AirshipSpec.kt

+4
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ abstract class AirshipSpec internal constructor(context: ReactApplicationContext
302302
@com.facebook.proguard.annotations.DoNotStrip
303303
abstract fun inAppIsPaused(promise: Promise)
304304

305+
@ReactMethod
306+
@com.facebook.proguard.annotations.DoNotStrip
307+
abstract fun inAppResendPendingEmbeddedEvent()
308+
305309
@ReactMethod
306310
@com.facebook.proguard.annotations.DoNotStrip
307311
abstract fun messageCenterGetUnreadCount(promise: Promise)
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
#Tue Aug 06 09:31:04 PDT 2024
12
distributionBase=GRADLE_USER_HOME
23
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
45
networkTimeout=10000
56
validateDistributionUrl=true
67
zipStoreBase=GRADLE_USER_HOME
7-
zipStorePath=wrapper/dists
8+
zipStorePath=wrapper/dists

example/ios/Podfile.lock

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ PODS:
1717
- Airship/Core
1818
- Airship/PreferenceCenter (18.7.2):
1919
- Airship/Core
20-
- AirshipFrameworkProxy (7.1.2):
20+
- AirshipFrameworkProxy (7.3.0):
2121
- Airship (= 18.7.2)
2222
- AirshipServiceExtension (18.7.2)
2323
- boost (1.83.0)
@@ -907,8 +907,8 @@ PODS:
907907
- React-Mapbuffer (0.73.4):
908908
- glog
909909
- React-debug
910-
- react-native-airship (19.2.0):
911-
- AirshipFrameworkProxy (= 7.1.2)
910+
- react-native-airship (19.3.0):
911+
- AirshipFrameworkProxy (= 7.3.0)
912912
- glog
913913
- RCT-Folly (= 2022.05.16.00)
914914
- React-Core
@@ -1280,7 +1280,7 @@ EXTERNAL SOURCES:
12801280

12811281
SPEC CHECKSUMS:
12821282
Airship: bb32ff2c5a811352da074480357d9f02dbb8f327
1283-
AirshipFrameworkProxy: dbd862dc6fb21b13e8b196458d626123e2a43a50
1283+
AirshipFrameworkProxy: 88a5e374efb5841e8cd84e63983c1ded123fe073
12841284
AirshipServiceExtension: 9c73369f426396d9fb9ff222d86d842fac76ba46
12851285
boost: d3f49c53809116a5d38da093a8aa78bf551aed09
12861286
DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953
@@ -1311,7 +1311,7 @@ SPEC CHECKSUMS:
13111311
React-jsinspector: 9ac353eccf6ab54d1e0a33862ba91221d1e88460
13121312
React-logger: 0a57b68dd2aec7ff738195f081f0520724b35dab
13131313
React-Mapbuffer: 63913773ed7f96b814a2521e13e6d010282096ad
1314-
react-native-airship: 54a39240587b06b2f683769a2ab838b7ee25b2e6
1314+
react-native-airship: 7fcefeebfac490aab222b93521e08ebd5b3d4581
13151315
react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b
13161316
React-nativeconfig: d7af5bae6da70fa15ce44f045621cf99ed24087c
13171317
React-NativeModulesApple: 0123905d5699853ac68519607555a9a4f5c7b3ac
@@ -1342,4 +1342,4 @@ SPEC CHECKSUMS:
13421342

13431343
PODFILE CHECKSUM: dbd88b0cf2e018eeff600431486ded3ce68933fb
13441344

1345-
COCOAPODS: 1.12.1
1345+
COCOAPODS: 1.15.2

example/src/screens/HomeScreen.tsx

+29-7
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import {
1212
Image,
1313
KeyboardAvoidingView,
1414
Platform,
15-
TouchableOpacity,
15+
TouchableOpacity
1616
} from 'react-native';
17-
import Airship, { EventType } from '@ua/react-native-airship';
17+
import Airship, { EventType, AirshipEmbeddedView} from '@ua/react-native-airship';
1818

1919
import styles from '../Styles';
2020
import NamedUserManagerCell from './Home Elements/NamedUserManagerCell';
@@ -46,6 +46,7 @@ export default function HomeScreen() {
4646
const [tags, setTags] = useState<string[]>([]);
4747
const [tagText, setTagText] = useState('');
4848
const [notificationsEnabled, setNotificationsEnabled] = useState(false);
49+
const [isEmbeddedReady, setEmbeddedReady] = useState(false)
4950

5051
const refreshTags = useCallback(async () => {
5152
const fetchedTags = await Airship.channel.getTags();
@@ -95,6 +96,8 @@ export default function HomeScreen() {
9596
console.error('Error getting notification status:', error);
9697
});
9798

99+
setEmbeddedReady(Airship.inApp.isEmbeddedReady("test"))
100+
98101
Airship.push.iOS
99102
.getAuthorizedNotificationSettings()
100103
.then((id) => {
@@ -141,6 +144,11 @@ export default function HomeScreen() {
141144
}
142145
);
143146

147+
Airship.inApp.addEmbeddedReadyListener("test", (isReady) => {
148+
console.log("Test " + isReady)
149+
setEmbeddedReady(isReady)
150+
});
151+
144152
return () => {
145153
subscription.remove();
146154
};
@@ -153,18 +161,32 @@ export default function HomeScreen() {
153161
keyboardVerticalOffset={Platform.OS === 'ios' ? 200 : 0}
154162
>
155163
<View style={{ flex: 1, flexShrink: 0, padding: 20 }}>
164+
165+
166+
{isEmbeddedReady ?
167+
(
168+
<View style={{ flex: 1 }}>
169+
<AirshipEmbeddedView
170+
embeddedId="test"
171+
style={{ flex: 1 }}
172+
/>
173+
</View>
174+
)
175+
: (
156176
<View
157177
style={{
158178
flex: 1,
159179
justifyContent: 'center',
160180
alignItems: 'center',
161181
}}
162182
>
163-
<Image
164-
style={[styles.backgroundIcon, { paddingBottom: 0 }]}
165-
source={require('./../img/airship-mark.png')}
166-
/>
167-
</View>
183+
<Image
184+
style={[styles.backgroundIcon, { paddingBottom: 0 }]}
185+
source={require('./../img/airship-mark.png')}
186+
/>
187+
</View>)}
188+
189+
168190

169191
<View style={{ flexDirection: 'column' }}>
170192
{channelId ? (

0 commit comments

Comments
 (0)