Skip to content

Commit dd35eef

Browse files
committed
feat: ios add databinding observability and useRive hook on ready
1 parent 2f0f278 commit dd35eef

11 files changed

Lines changed: 403 additions & 104 deletions

example/ios/example/Info.plist

Lines changed: 76 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,79 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
4-
<dict>
5-
<key>CADisableMinimumFrameDurationOnPhone</key>
6-
<true/>
7-
<key>CFBundleDevelopmentRegion</key>
8-
<string>$(DEVELOPMENT_LANGUAGE)</string>
9-
<key>CFBundleDisplayName</key>
10-
<string>example</string>
11-
<key>CFBundleExecutable</key>
12-
<string>$(EXECUTABLE_NAME)</string>
13-
<key>CFBundleIdentifier</key>
14-
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
15-
<key>CFBundleInfoDictionaryVersion</key>
16-
<string>6.0</string>
17-
<key>CFBundleName</key>
18-
<string>$(PRODUCT_NAME)</string>
19-
<key>CFBundlePackageType</key>
20-
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
21-
<key>CFBundleShortVersionString</key>
22-
<string>1.0.0</string>
23-
<key>CFBundleSignature</key>
24-
<string>????</string>
25-
<key>CFBundleURLTypes</key>
26-
<array>
27-
<dict>
28-
<key>CFBundleURLSchemes</key>
29-
<array>
30-
<string>myapp</string>
31-
<string>com.anonymous.example</string>
32-
</array>
33-
</dict>
34-
</array>
35-
<key>CFBundleVersion</key>
36-
<string>1</string>
37-
<key>LSMinimumSystemVersion</key>
38-
<string>12.0</string>
39-
<key>LSRequiresIPhoneOS</key>
40-
<true/>
41-
<key>NSAppTransportSecurity</key>
42-
<dict>
43-
<key>NSAllowsArbitraryLoads</key>
44-
<false/>
45-
<key>NSAllowsLocalNetworking</key>
46-
<true/>
47-
</dict>
48-
<key>NSUserActivityTypes</key>
49-
<array>
50-
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
51-
</array>
52-
<key>UILaunchStoryboardName</key>
53-
<string>SplashScreen</string>
54-
<key>UIRequiredDeviceCapabilities</key>
55-
<array>
56-
<string>arm64</string>
57-
</array>
58-
<key>UIRequiresFullScreen</key>
59-
<false/>
60-
<key>UIStatusBarStyle</key>
61-
<string>UIStatusBarStyleDefault</string>
62-
<key>UISupportedInterfaceOrientations</key>
63-
<array>
64-
<string>UIInterfaceOrientationPortrait</string>
65-
<string>UIInterfaceOrientationPortraitUpsideDown</string>
66-
</array>
67-
<key>UISupportedInterfaceOrientations~ipad</key>
68-
<array>
69-
<string>UIInterfaceOrientationPortrait</string>
70-
<string>UIInterfaceOrientationPortraitUpsideDown</string>
71-
<string>UIInterfaceOrientationLandscapeLeft</string>
72-
<string>UIInterfaceOrientationLandscapeRight</string>
73-
</array>
74-
<key>UIUserInterfaceStyle</key>
75-
<string>Automatic</string>
76-
<key>UIViewControllerBasedStatusBarAppearance</key>
77-
<false/>
78-
</dict>
79-
</plist>
4+
<dict>
5+
<key>CADisableMinimumFrameDurationOnPhone</key>
6+
<true/>
7+
<key>CFBundleDevelopmentRegion</key>
8+
<string>$(DEVELOPMENT_LANGUAGE)</string>
9+
<key>CFBundleDisplayName</key>
10+
<string>example</string>
11+
<key>CFBundleExecutable</key>
12+
<string>$(EXECUTABLE_NAME)</string>
13+
<key>CFBundleIdentifier</key>
14+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
15+
<key>CFBundleInfoDictionaryVersion</key>
16+
<string>6.0</string>
17+
<key>CFBundleName</key>
18+
<string>$(PRODUCT_NAME)</string>
19+
<key>CFBundlePackageType</key>
20+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
21+
<key>CFBundleShortVersionString</key>
22+
<string>1.0.0</string>
23+
<key>CFBundleSignature</key>
24+
<string>????</string>
25+
<key>CFBundleURLTypes</key>
26+
<array>
27+
<dict>
28+
<key>CFBundleURLSchemes</key>
29+
<array>
30+
<string>myapp</string>
31+
<string>com.anonymous.example</string>
32+
</array>
33+
</dict>
34+
</array>
35+
<key>CFBundleVersion</key>
36+
<string>1</string>
37+
<key>LSMinimumSystemVersion</key>
38+
<string>12.0</string>
39+
<key>LSRequiresIPhoneOS</key>
40+
<true/>
41+
<key>NSAppTransportSecurity</key>
42+
<dict>
43+
<key>NSAllowsArbitraryLoads</key>
44+
<false/>
45+
<key>NSAllowsLocalNetworking</key>
46+
<true/>
47+
</dict>
48+
<key>NSUserActivityTypes</key>
49+
<array>
50+
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
51+
</array>
52+
<key>UILaunchStoryboardName</key>
53+
<string>SplashScreen</string>
54+
<key>UIRequiredDeviceCapabilities</key>
55+
<array>
56+
<string>arm64</string>
57+
</array>
58+
<key>UIRequiresFullScreen</key>
59+
<false/>
60+
<key>UIStatusBarStyle</key>
61+
<string>UIStatusBarStyleDefault</string>
62+
<key>UISupportedInterfaceOrientations</key>
63+
<array>
64+
<string>UIInterfaceOrientationPortrait</string>
65+
<string>UIInterfaceOrientationPortraitUpsideDown</string>
66+
</array>
67+
<key>UISupportedInterfaceOrientations~ipad</key>
68+
<array>
69+
<string>UIInterfaceOrientationPortrait</string>
70+
<string>UIInterfaceOrientationPortraitUpsideDown</string>
71+
<string>UIInterfaceOrientationLandscapeLeft</string>
72+
<string>UIInterfaceOrientationLandscapeRight</string>
73+
</array>
74+
<key>UIUserInterfaceStyle</key>
75+
<string>Automatic</string>
76+
<key>UIViewControllerBasedStatusBarAppearance</key>
77+
<false/>
78+
</dict>
79+
</plist>

ios/RNPropertyType.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// RNPropertyType.swift
3+
// rive-react-native
4+
//
5+
// Created by Peter G Hayes on 02/05/2025.
6+
//
7+
8+
import Foundation
9+
10+
enum RNPropertyType: String {
11+
case Number = "number"
12+
case String = "string"
13+
case Boolean = "boolean"
14+
case Color = "color"
15+
case Trigger = "trigger"
16+
case Enum = "enum"
17+
18+
static func mapToRNPropertyType(value: String) -> RNPropertyType {
19+
if let rnEnum = RNPropertyType(rawValue: value) {
20+
return rnEnum
21+
} else {
22+
fatalError("Unsupported property type: \(value)")
23+
}
24+
}
25+
}

ios/RiveReactNative-Bridging-Header.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
#import <React/RCTUtils.h>
66
#import <React/RCTExceptionsManager.h>
77
#import <React/RCTView.h>
8+
#import <React/RCTEventEmitter.h>

ios/RiveReactNative.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
F8682EC52DC968570042128B /* RiveReactNativeEventModule.m in Sources */ = {isa = PBXBuildFile; fileRef = F8682EC42DC968570042128B /* RiveReactNativeEventModule.m */; };
1011
F87A07662D7B4020000B39D0 /* RiveReactNativeModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87A07652D7B4020000B39D0 /* RiveReactNativeModule.swift */; };
1112
F87A07682D7B4092000B39D0 /* RiveReactNativeModuleBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = F87A07672D7B4092000B39D0 /* RiveReactNativeModuleBridge.m */; };
1213
/* End PBXBuildFile section */
@@ -29,6 +30,8 @@
2930
B3E7B5891CC2AC0600A0062D /* RiveReactNative.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RiveReactNative.m; sourceTree = "<group>"; };
3031
F4FF95D5245B92E700C19C63 /* RiveReactNative-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RiveReactNative-Bridging-Header.h"; sourceTree = "<group>"; };
3132
F4FF95D6245B92E800C19C63 /* RiveReactNative.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RiveReactNative.swift; sourceTree = "<group>"; };
33+
F8682EC42DC968570042128B /* RiveReactNativeEventModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RiveReactNativeEventModule.m; sourceTree = "<group>"; };
34+
F8682EC62DC968710042128B /* RiveReactNativeEventModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RiveReactNativeEventModule.h; sourceTree = "<group>"; };
3235
F86B6E412C0DCEE5001AD21C /* RiveReactNativeRendererModuleBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RiveReactNativeRendererModuleBridge.m; sourceTree = "<group>"; };
3336
F86B6E422C0DCEFF001AD21C /* RiveReactNativeRendererModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RiveReactNativeRendererModule.swift; sourceTree = "<group>"; };
3437
F86B6E432C0DCF12001AD21C /* RNRiveRendererType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNRiveRendererType.swift; sourceTree = "<group>"; };
@@ -58,6 +61,8 @@
5861
58B511D21A9E6C8500147676 = {
5962
isa = PBXGroup;
6063
children = (
64+
F8682EC62DC968710042128B /* RiveReactNativeEventModule.h */,
65+
F8682EC42DC968570042128B /* RiveReactNativeEventModule.m */,
6166
F87A07672D7B4092000B39D0 /* RiveReactNativeModuleBridge.m */,
6267
F87A07652D7B4020000B39D0 /* RiveReactNativeModule.swift */,
6368
F86B6E432C0DCF12001AD21C /* RNRiveRendererType.swift */,
@@ -129,6 +134,7 @@
129134
buildActionMask = 2147483647;
130135
files = (
131136
F87A07662D7B4020000B39D0 /* RiveReactNativeModule.swift in Sources */,
137+
F8682EC52DC968570042128B /* RiveReactNativeEventModule.m in Sources */,
132138
F87A07682D7B4092000B39D0 /* RiveReactNativeModuleBridge.m in Sources */,
133139
);
134140
runOnlyForDeploymentPostprocessing = 0;

ios/RiveReactNativeEventModule.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// RiveReactNativeEventModule.h
3+
// RiveReactNative
4+
//
5+
// Created by Peter G Hayes on 05/05/2025.
6+
// Copyright © 2025 Facebook. All rights reserved.
7+
//
8+
9+
#ifndef RiveReactNativeEventModule_h
10+
#define RiveReactNativeEventModule_h
11+
12+
#import <React/RCTEventEmitter.h>
13+
#import <React/RCTBridgeModule.h>
14+
15+
@interface RiveReactNativeEventModule : RCTEventEmitter <RCTBridgeModule>
16+
- (BOOL)isListenerActive:(NSString *)eventName;
17+
- (void)removeListenerByName:(NSString *)eventName;
18+
@end
19+
20+
#endif /* RiveReactNativeEventModule_h */

ios/RiveReactNativeEventModule.m

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// RiveReactNativeEventModule.m
3+
// RiveReactNative
4+
//
5+
// Created by Peter G Hayes on 05/05/2025.
6+
// Copyright © 2025 Facebook. All rights reserved.
7+
//
8+
9+
#import "RiveReactNativeEventModule.h"
10+
11+
@implementation RiveReactNativeEventModule {
12+
BOOL hasListeners;
13+
NSMutableSet<NSString *> *_activeListeners;
14+
}
15+
16+
RCT_EXPORT_MODULE();
17+
18+
- (instancetype)init {
19+
self = [super init];
20+
if (self) {
21+
_activeListeners = [NSMutableSet new];
22+
}
23+
return self;
24+
}
25+
26+
// Called by React Native to determine which listeners are supported in JS
27+
- (NSArray<NSString *> *)supportedEvents {
28+
return _activeListeners.allObjects;
29+
}
30+
31+
// Called by React Native when a listener is added from JS
32+
- (void)addListener:(NSString *)eventName {
33+
[_activeListeners addObject:eventName];
34+
[super addListener:eventName];
35+
}
36+
37+
// Called by React Native when removeListeners is called from JS
38+
// We intentionally do not clean up all the listeners in
39+
// _activeListeners, as this object is shared between all
40+
// created views. We only ever clean up particular listeners
41+
// tied to a view. See removeListenerByName.
42+
- (void)removeListeners:(double)count {
43+
[super removeListeners:count];
44+
}
45+
46+
// Used to manually clean up the listeners when a view is disposed
47+
- (void)removeListenerByName:(NSString *)eventName {
48+
[_activeListeners removeObject:eventName];
49+
}
50+
51+
// Used to determine if a particular listener has already been added.
52+
// Used in RiveReactNativeView to send a "loaded" event to JS when Rive
53+
// is ready, which we only want to do if the listener was actually added
54+
// from JS (as part of the useRive() hook).
55+
- (BOOL)isListenerActive:(NSString *)eventName {
56+
return [_activeListeners containsObject:eventName];
57+
}
58+
59+
@end

0 commit comments

Comments
 (0)