Unverified Commit 9e4a4d24 authored by Diego Mello's avatar Diego Mello Committed by GitHub
Browse files

[CHORE] Use react-native-firebase (#928)

We need to migrate from deprecated react-native-fabric to react-native-firebase.
This PR enables following Firebase features:
* Analytics
* Crashlytics
* Performance

It also tracks screen view without the necessity of HOC.

Future work:
I won't do it in this PR because it's large enough, but we need to log more app events, like 'sent_message', 'open_admin', 'media_upload', etc.
parent 9d795809
......@@ -131,18 +131,6 @@ jobs:
echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties
if [[ $FABRIC_KEY ]]; then
echo -e "" > ./app/fabric.properties
echo -e "apiKey=$FABRIC_KEY" >> ./app/fabric.properties
echo -e "apiSecret=$FABRIC_SECRET" >> ./app/fabric.properties
fi
# - run:
# name: Install Android Depedencies
# command: |
# cd android
# ./gradlew androidDependencies
- run:
name: Build Android App
command: |
......@@ -201,25 +189,12 @@ jobs:
command: |
yarn
# - run:
# name: Fix known build error
# command: |
# # Fix error https://github.com/facebook/react-native/issues/14382
# cd node_modules/react-native/scripts/
# curl https://raw.githubusercontent.com/facebook/react-native/5c53f89dd86160301feee024bce4ce0c89e8c187/scripts/ios-configure-glog.sh > ios-configure-glog.sh
# chmod +x ios-configure-glog.sh
- run:
name: Fastlane Build
no_output_timeout: 1200
command: |
cd ios
agvtool new-version -all $CIRCLE_BUILD_NUM
/usr/libexec/PlistBuddy -c "Set Fabric:APIKey $FABRIC_KEY" ./RocketChatRN/Info.plist
if [[ $FABRIC_KEY ]]; then
echo -e > "./Fabric.framework/run $FABRIC_KEY $FABRIC_SECRET" > ./RocketChatRN/Fabric.sh
fi
if [[ $MATCH_KEYCHAIN_NAME ]]; then
fastlane ios release
......
apply plugin: "com.android.application"
apply plugin: "io.fabric"
apply plugin: "com.google.firebase.firebase-perf"
import com.android.build.OutputFile
......@@ -163,47 +165,8 @@ android {
}
}
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
// These docs use an open ended version so that our plugin
// can be updated quickly in response to Android tooling updates
// We recommend changing it to the latest version from our changelog:
// https://docs.fabric.io/android/changelog.html#fabric-gradle-plugin
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: 'io.fabric'
repositories {
maven { url 'https://maven.fabric.io/public' }
}
configurations.all {
resolutionStrategy {
eachDependency { DependencyResolveDetails details ->
if (details.requested.name == 'play-services-base') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1'
}
if (details.requested.name == 'play-services-tasks') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1'
}
if (details.requested.name == 'play-services-stats') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1'
}
if (details.requested.name == 'play-services-basement') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1'
}
}
}
}
dependencies {
implementation project(':react-native-firebase')
implementation project(':react-native-webview')
implementation project(':react-native-orientation-locker')
implementation project(':react-native-splash-screen')
......@@ -213,7 +176,6 @@ dependencies {
implementation project(':react-native-gesture-handler')
implementation project(':react-native-image-crop-picker')
implementation project(':react-native-i18n')
implementation project(':react-native-fabric')
implementation project(':react-native-audio')
implementation project(":reactnativekeyboardinput")
implementation project(':react-native-video')
......@@ -232,10 +194,12 @@ dependencies {
implementation 'com.facebook.fresco:animated-gif:1.10.0'
implementation 'com.facebook.fresco:animated-webp:1.10.0'
implementation 'com.facebook.fresco:webpsupport:1.10.0'
implementation "com.google.firebase:firebase-core:16.0.1"
implementation "com.google.firebase:firebase-messaging:17.3.4"
implementation "com.google.android.gms:play-services-base:16.1.0"
implementation "com.google.firebase:firebase-messaging:18.0.0"
implementation "com.google.firebase:firebase-core:16.0.9"
implementation "com.google.firebase:firebase-perf:16.2.5"
implementation('com.crashlytics.sdk.android:crashlytics:2.9.5@aar') {
transitive = true;
transitive = true
}
}
......@@ -247,4 +211,3 @@ task copyDownloadableDepsToLibs(type: Copy) {
}
apply plugin: 'com.google.gms.google-services'
com.google.gms.googleservices.GoogleServicesPlugin.config.disableVersionCheck = true
apiKey=ef3f46fdf18479fd3e1b9b78d0ec73751a255e14
apiSecret=e8e3d04c28bc04acd009484da5bb9d1440c4f53851564e9f95c3225ec8b0bc76
\ No newline at end of file
......@@ -25,15 +25,20 @@
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
"other_platform_oauth_client": [
{
"client_id": "673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "673693445664-jbf9m30ta163gobjfp0v7j1v7kpo7kmv.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "chat.rocket.reactnative"
}
}
]
}
}
},
......@@ -46,19 +51,19 @@
},
"oauth_client": [
{
"client_id": "673693445664-hrjftksij02vqtd467ln2cubvu48ft5j.apps.googleusercontent.com",
"client_id": "673693445664-k0mvosdjoe5dbvqce3b377ckabb5dgu8.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "chat.rocket.android",
"certificate_hash": "41cf750df786a6d9da712a98a629d0c8391876d6"
"certificate_hash": "33fa8582794176014a59054192e261bfad0e5273"
}
},
{
"client_id": "673693445664-k0mvosdjoe5dbvqce3b377ckabb5dgu8.apps.googleusercontent.com",
"client_id": "673693445664-hrjftksij02vqtd467ln2cubvu48ft5j.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "chat.rocket.android",
"certificate_hash": "33fa8582794176014a59054192e261bfad0e5273"
"certificate_hash": "41cf750df786a6d9da712a98a629d0c8391876d6"
}
},
{
......@@ -72,28 +77,20 @@
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 2,
"other_platform_oauth_client": [
{
"client_id": "673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "673693445664-dumairnsk1sbkca5nmsq2b5kdglqpc0a.apps.googleusercontent.com",
"client_id": "673693445664-jbf9m30ta163gobjfp0v7j1v7kpo7kmv.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "chat.rocket.ios",
"app_store_id": "1148741252"
"bundle_id": "chat.rocket.reactnative"
}
}
]
},
"ads_service": {
"status": 2
}
}
},
......@@ -132,28 +129,20 @@
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 2,
"other_platform_oauth_client": [
{
"client_id": "673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "673693445664-dumairnsk1sbkca5nmsq2b5kdglqpc0a.apps.googleusercontent.com",
"client_id": "673693445664-jbf9m30ta163gobjfp0v7j1v7kpo7kmv.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "chat.rocket.ios",
"app_store_id": "1148741252"
"bundle_id": "chat.rocket.reactnative"
}
}
]
},
"ads_service": {
"status": 2
}
}
},
......@@ -176,15 +165,20 @@
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
"other_platform_oauth_client": [
{
"client_id": "673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "673693445664-jbf9m30ta163gobjfp0v7j1v7kpo7kmv.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "chat.rocket.reactnative"
}
}
]
}
}
},
......@@ -215,28 +209,20 @@
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 2,
"other_platform_oauth_client": [
{
"client_id": "673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "673693445664-dumairnsk1sbkca5nmsq2b5kdglqpc0a.apps.googleusercontent.com",
"client_id": "673693445664-jbf9m30ta163gobjfp0v7j1v7kpo7kmv.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "chat.rocket.ios",
"app_store_id": "1148741252"
"bundle_id": "chat.rocket.reactnative"
}
}
]
},
"ads_service": {
"status": 2
}
}
}
......
......@@ -3,6 +3,10 @@ package chat.rocket.reactnative;
import android.app.Application;
import com.facebook.react.ReactApplication;
import io.invertase.firebase.RNFirebasePackage;
import io.invertase.firebase.fabric.crashlytics.RNFirebaseCrashlyticsPackage;
import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage;
import io.invertase.firebase.perf.RNFirebasePerformancePackage;
import com.reactnativecommunity.webview.RNCWebViewPackage;
import org.wonday.orientation.OrientationPackage;
import org.devio.rn.splashscreen.SplashScreenReactPackage;
......@@ -15,11 +19,9 @@ import com.AlexanderZaytsev.RNI18n.RNI18nPackage;
import com.reactnative.ivpusic.imagepicker.PickerPackage;
import com.RNFetchBlob.RNFetchBlobPackage;
import com.brentvatne.react.ReactVideoPackage;
import com.crashlytics.android.Crashlytics;
import com.dylanvann.fastimage.FastImageViewPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.rnim.rn.audio.ReactNativeAudioPackage;
import com.smixx.fabric.FabricPackage;
import com.wix.reactnativekeyboardinput.KeyboardInputPackage;
import com.wix.reactnativenotifications.RNNotificationsPackage;
import com.wix.reactnativenotifications.core.AppLaunchHelper;
......@@ -30,7 +32,6 @@ import com.wix.reactnativenotifications.core.notification.IPushNotification;
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.actionsheet.ActionSheetPackage;
import io.fabric.sdk.android.Fabric;
import io.realm.react.RealmReactPackage;
import com.swmansion.rnscreens.RNScreensPackage;
......@@ -52,6 +53,10 @@ public class MainApplication extends Application implements ReactApplication, IN
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RNFirebasePackage(),
new RNFirebaseCrashlyticsPackage(),
new RNFirebaseAnalyticsPackage(),
new RNFirebasePerformancePackage(),
new RNCWebViewPackage(),
new OrientationPackage(),
new SplashScreenReactPackage(),
......@@ -67,7 +72,6 @@ public class MainApplication extends Application implements ReactApplication, IN
new ReactNativeAudioPackage(),
new KeyboardInputPackage(MainApplication.this),
new RocketChatNativePackage(),
new FabricPackage(),
new FastImageViewPackage(),
new RNI18nPackage(),
new RNNotificationsPackage(MainApplication.this)
......@@ -88,7 +92,6 @@ public class MainApplication extends Application implements ReactApplication, IN
@Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
SoLoader.init(this, /* native exopackage */ false);
}
......
......@@ -11,10 +11,15 @@ buildscript {
mavenLocal()
google()
jcenter()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath 'com.google.gms:google-services:4.0.1'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.25.4'
classpath 'com.google.firebase:firebase-plugins:1.1.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
......
rootProject.name = 'RocketChatRN'
include ':react-native-firebase'
project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android')
include ':react-native-webview'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
include ':react-native-orientation-locker'
......@@ -21,8 +23,6 @@ include ':react-native-i18n'
project(':react-native-i18n').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-i18n/android')
include ':react-native-fast-image'
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')
include ':react-native-fabric'
project(':react-native-fabric').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fabric/android')
include ':react-native-audio'
project(':react-native-audio').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-audio/android')
include ':reactnativekeyboardinput'
......
......@@ -5,6 +5,7 @@ import {
import { Provider } from 'react-redux';
import { useScreens } from 'react-native-screens'; // eslint-disable-line import/no-unresolved
import { Linking } from 'react-native';
import firebase from 'react-native-firebase';
import { appInit } from './actions';
import { deepLinkingOpen } from './actions/deepLinking';
......@@ -204,6 +205,28 @@ const App = createAppContainer(createSwitchNavigator(
}
));
// gets the current screen from navigation state
const getActiveRouteName = (navigationState) => {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
};
const onNavigationStateChange = (prevState, currentState) => {
const currentScreen = getActiveRouteName(currentState);
const prevScreen = getActiveRouteName(prevState);
if (prevScreen !== currentScreen) {
firebase.analytics().setCurrentScreen(currentScreen);
}
};
export default class Root extends React.Component {
constructor(props) {
super(props);
......@@ -244,6 +267,7 @@ export default class Root extends React.Component {
ref={(navigatorRef) => {
Navigation.setTopLevelNavigator(navigatorRef);
}}
onNavigationStateChange={onNavigationStateChange}
/>
</Provider>
);
......
import { Answers } from 'react-native-fabric';
export default fn => (...params) => {
try {
fn(...params);
......@@ -8,7 +6,6 @@ export default fn => (...params) => {
if (typeof error !== 'object') {
error = { error };
}
Answers.logCustom('error', error);
if (__DEV__) {
alert(error);
}
......
import { Answers } from 'react-native-fabric';
import firebase from 'react-native-firebase';
export default (event, error) => {
if (typeof error !== 'object') {
error = { error };
}
Answers.logCustom(event);
firebase.analytics().logEvent(event);
if (__DEV__) {
console.warn(event, error);
}
......
......@@ -5,7 +5,6 @@ import { SafeAreaView } from 'react-navigation';
import { connect } from 'react-redux';
import I18n from '../../i18n';
import LoggedView from '../View';
import StatusBar from '../../containers/StatusBar';
import { DrawerButton } from '../../containers/HeaderButton';
import styles from '../Styles';
......@@ -14,8 +13,7 @@ import styles from '../Styles';
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
authToken: state.login.user && state.login.user.token
}))
/** @extends React.Component */
export default class AdminPanelView extends LoggedView {
export default class AdminPanelView extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerLeft: <DrawerButton navigation={navigation} />,
title: I18n.t('Admin_Panel')
......@@ -26,10 +24,6 @@ export default class AdminPanelView extends LoggedView {
authToken: PropTypes.string
}
constructor(props) {
super('AdminPanelView', props);
}
render() {
const { baseUrl, authToken } = this.props;
if (!baseUrl) {
......
......@@ -8,7 +8,6 @@ import { SafeAreaView } from 'react-navigation';
import equal from 'deep-equal';
import Loading from '../containers/Loading';
import LoggedView from './View';
import { createChannelRequest as createChannelRequestAction } from '../actions/createChannel';
import { removeUser as removeUserAction } from '../actions/selectedUsers';
import sharedStyles from './Styles';
......@@ -93,8 +92,7 @@ const styles = StyleSheet.create({
create: data => dispatch(createChannelRequestAction(data)),
removeUser: user => dispatch(removeUserAction(user))
}))
/** @extends React.Component */
export default class CreateChannelView extends LoggedView {
export default class CreateChannelView extends React.Component {
static navigationOptions = ({ navigation }) => {
const submit = navigation.getParam('submit', () => {});
const showSubmit = navigation.getParam('showSubmit');
......@@ -128,14 +126,11 @@ export default class CreateChannelView extends LoggedView {
})
};
constructor(props) {
super('CreateChannelView', props);
this.state = {
channelName: '',
type: true,
readOnly: false,
broadcast: false
};
state = {
channelName: '',
type: true,
readOnly: false,
broadcast: false
}
componentDidMount() {
......
......@@ -3,7 +3,6 @@ import { Text, ScrollView } from 'react-native';
import { SafeAreaView } from 'react-navigation';
import PropTypes from 'prop-types';
import LoggedView from './View';
import KeyboardView from '../presentation/KeyboardView';
import TextInput from '../containers/TextInput';
import Button from '../containers/Button';
......@@ -15,8 +14,7 @@ import I18n from '../i18n';
import RocketChat from '../lib/rocketchat';
import StatusBar from '../containers/StatusBar';
/** @extends React.Component */
export default class ForgotPasswordView extends LoggedView {
export default class ForgotPasswordView extends React.Component {
static navigationOptions = ({ navigation }) => {
const title = navigation.getParam('title', 'Rocket.Chat');
return {
......@@ -28,14 +26,10 @@ export default class ForgotPasswordView extends LoggedView {
navigation: PropTypes.object
}
constructor(props) {
super('ForgotPasswordView', props);
this.state = {
email: '',
invalidEmail: true,
isFetching: false
};
state = {
email: '',
invalidEmail: true,
isFetching: false
}
componentDidMount() {
......
......@@ -9,7 +9,6 @@ import { connect } from 'react-redux';
import sharedStyles from './Styles';
import scrollPersistTaps from '../utils/scrollPersistTaps';
import LoggedView from './View';
import I18n from '../i18n';
import DisclosureIndicator from '../containers/DisclosureIndicator';
import StatusBar from '../containers/StatusBar';
......@@ -56,8 +55,7 @@ const Separator = () => <View style={styles.separator} />;
@connect(state => ({
server: state.server.server
}))
/** @extends React.Component */
export default class LegalView extends LoggedView {
export default class LegalView extends React.Component {
static navigationOptions = () => ({
title: I18n.t('Legal')
})
......@@ -66,10 +64,6 @@ export default class LegalView extends LoggedView {
server: PropTypes.string
}
constructor(props) {
super('LegalView', props);
}
onPressItem = ({ route }) => {
const { server } = this.props;
if (!server) {
......
......@@ -9,7 +9,6 @@ import { SafeAreaView } from 'react-navigation';
import { RectButton, BorderlessButton } from 'react-native-gesture-handler';
import equal from 'deep-equal';
import LoggedView from './View';
import sharedStyles from './Styles';
import scrollPersistTaps from '../utils/scrollPersistTaps';
import random from '../utils/random';
......@@ -94,8 +93,7 @@ const SERVICES_COLLAPSED_HEIGHT = 174;
Site_Name: state.settings.Site_Name,
services: state.login.services
}))
/** @extends React.Component */
export default class LoginSignupView extends LoggedView {
export default class LoginSignupView extends React.Component {
static navigationOptions = ({ navigation }) => {