Created
January 25, 2018 21:11
-
-
Save hgale/9df98958f15a7bfe62af9a3537120a9c to your computer and use it in GitHub Desktop.
BrownFieldsample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool | |
// Warm up ReactNative bridge and fetch latest screens | |
RNEventController.applicationDidLaunch() | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "ExampleReactNative", | |
"version": "0.0.1", | |
"private": true, | |
"scripts": { | |
"postinstall": "sed -i '' 's#<RCTAnimation/RCTValueAnimatedNode.h>#\"RCTValueAnimatedNode.h\"#g' ./node_modules/react-native/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h; sed -i '' 's#<fishhook/fishhook.h>#\"fishhook.h\"#g' ./node_modules/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m; sed -i '' 's#\"RCTBridgeModule.h\"#<React/RCTBridgeModule.h>#g' ./node_modules/react-native-event-bridge/ios/MSREventBridge.h; sed -i '' 's#\"RCTEventEmitter.h\"#<React/RCTEventEmitter.h>#g' ./node_modules/react-native-event-bridge/ios/MSREventBridge.h", | |
"start": "node node_modules/react-native/local-cli/cli.js start", | |
"test": "jest" | |
}, | |
"dependencies": { | |
"lodash": "4.2.0", | |
"lodash.assign": "^4.2.0", | |
"node-pre-gyp": "^0.6.39", | |
"react": "16.0.0-beta.5", | |
"react-native": "0.49.1", | |
"react-native-code-push": "^5.2.1", | |
"react-native-event-bridge": "^0.7.0", | |
"stacktrace-js": "^1.1.0" | |
}, | |
"devDependencies": { | |
"babel-jest": "21.2.0", | |
"babel-preset-react-native": "4.0.0", | |
"jest": "21.2.1", | |
"react-test-renderer": "16.0.0-beta.5" | |
}, | |
"jest": { | |
"preset": "react-native" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Root component on JS side of bridge: | |
class ReactNative extends React.Component { | |
constructor(props) { | |
super(props); | |
error.init(this); | |
} | |
componentDidMount() { | |
const { screen, sendSupportedScreens } = this.props; | |
if (sendSupportedScreens) { | |
this.sendSupportedScreens(); | |
this.getUpdateMetadata(); | |
} else { | |
// This is the analytics event that we are seeing the discrepency in, i.e 66% drop off versus the native side | |
logEvent(this, analyticsEvents.ViewScreen, {screen:screen}); | |
} | |
if (screen === Screens.Query) { | |
CodePush.sync({ installMode: CodePush.InstallMode.IMMEDIATE }); | |
} | |
} | |
render() { | |
const { screen } = this.props; | |
let selectedScreen = <Query {...this.props} /> | |
if (screen === Screens.ExpiredScreenOne) { | |
selectedScreen = <ExpiredScreenOne {...this.props} /> | |
} | |
if (screen === Screens.ExpiredScreenTwo) { | |
selectedScreen = <ExpiredScreenTwo {...this.props} /> | |
} | |
return (selectedScreen); | |
} | |
} | |
} | |
ReactNative = CodePush(codePushOptions)(ReactNative); | |
AppRegistry.registerComponent('ExampleReactNative', () => ReactNative); | |
// Analytics log function | |
function logEvent(component, event, properties) { | |
if (!isReactComponent(component)) { | |
throw new TypeError("'component' parameter is null or invalid."); | |
} | |
if (!isString(event)) { | |
throw new TypeError("'event' parameter must be a string."); | |
} | |
if (!isDictionary(properties)) { | |
throw new TypeError("'properties' parameter must be a dictionary."); | |
} | |
let info = { | |
event: event, | |
properties: properties | |
} | |
EventBridge.emitEvent(component, | |
eventsInternal.AnalyticsLogEvent, | |
{info:info}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
public typealias RNEventDictionary = [AnyHashable: Any] | |
public typealias RNEventHandler = (_ info: RNEventDictionary?) -> () | |
/// Simple event wrapper for performing generic work | |
public struct RNEvent { | |
// MARK: - Properties | |
/// The unique name of this event | |
public let name: String | |
/// A closure to execute arbitrary logic when this event is fired | |
public let handler: RNEventHandler | |
// MARK: - Convenience Initializers | |
/// Creates a new event with a unique name and handler for arbitrary logic | |
/// | |
/// - Parameters: | |
/// - name: The unique name of this event | |
/// - handler: A closure to execute arbitrary logic when this event is fired | |
public init(name: String, handler: @escaping RNEventHandler) { | |
self.name = name | |
self.handler = handler | |
} | |
/// Creates a new event with a unique name and handler for arbitrary logic | |
/// | |
/// - Parameters: | |
/// - name: The unique name of this event | |
/// - handler: A closure to execute arbitrary logic when this event is fired | |
public init(named name: RNEventName, handler: @escaping RNEventHandler) { | |
self.name = name.rawValue | |
self.handler = handler | |
} | |
} | |
// MARK: - Equatable | |
extension RNEvent: Equatable { | |
public static func ==(lhs: RNEvent, rhs: RNEvent) -> Bool { | |
return lhs.name == rhs.name | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open class RNEventController: UIViewController { | |
open class func applicationDidLaunch() { | |
// Initialize the event bridge | |
_ = RNEventController.eventBridge | |
} | |
/// The event bridge which we'll re-use throughout the app to keep React warmed up and snappy | |
fileprivate static let eventBridge = RCTBridge(bundleURL: RNEventController.jsCodeLocation, moduleProvider: nil, launchOptions: nil) | |
fileprivate static var jsCodeLocation: URL? { | |
// Development loads bundle from local node server | |
let localServerUrl = URL(string: "http://localhost:8081/index.ios.bundle?platform=ios&dev=true") | |
// Production loads minified bundle | |
let bundleUrl = CodePush.bundleURL(forResource: "main", withExtension: "jsbundle", subdirectory: nil, bundle: Bundle(for: RNEventController.self)) | |
return self.isInDeveloperMode ? localServerUrl : bundleUrl | |
} | |
fileprivate static let isInDeveloperMode = false | |
} | |
// MARK: - MSREventBridgeEventReceiver | |
extension RNEventController: MSREventBridgeEventReceiver { | |
public func onEvent(withName name: String?, info: [AnyHashable : Any]?) { | |
guard let event = self.events.first(where: { $0.name == name }) else { | |
if let name = name { self.handleMissingEvent(named: name) } | |
return | |
} | |
// This casting is important or it'll crash | |
let infoDictionary = info as? [String: Any] | |
// All events emitted from JS are wrapped in an outer `info` key | |
event.handler(infoDictionary?[RNKeys.info] as? [String: Any]) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The screen where we are seeing the discrepancy in events: | |
final class RNUpsellController: RNEventController { | |
init(screen: String, feature: AppFeature? = nil, completion: SuccessCallback? = nil) { | |
self.feature = feature | |
self.completion = completion | |
let status = App.premium.premiumStatus | |
self.source = status.upsellSource | |
let properties = RNUpsellController.viewProperties(screen: screen, status: status) | |
super.init(screen: screen, properties: properties) | |
self.setupEvents() | |
self.logViewSeen() | |
} | |
// This is the native analytics event that gets fired when this screen gets displayed, works as expected | |
override func logViewSeen() { | |
super.logViewSeen() | |
if let exp = PhotosSwitchboard.experiment(named: .featureUpsell) { | |
exp.track(event: AMPLITUDE_EVENT_ACCOUNT_STATUS_VIEW) | |
} | |
} | |
/// Creates a bridge for ReactNative to send analytics events to native | |
// Issue with analytics discrepancy occurs here, in testing and on my device this all appears to work | |
self.add(event: RNEvent(named: .AnalyticsLogEvent) { info in | |
guard let info = info, | |
let event = info[RNKeys.event] as? String | |
else { return } | |
let properties = info[RNKeys.properties] as? [String: Any] | |
RNAnalyticsProvider.log(event: event, properties: properties) | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment