Replace Mixpanel with Firebase (Google) analytics (#535)
* replace mixpanel with firebase analytics * add encrypted google-services.json file
This commit is contained in:
parent
73d91f7268
commit
7a7e96388b
20 changed files with 114 additions and 115 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -12,3 +12,4 @@ src/main/assets/index.android.bundle.meta
|
||||||
lbry-android.keystore
|
lbry-android.keystore
|
||||||
p4a/pythonforandroid/bootstraps/lbry/build/templates/google-services.json
|
p4a/pythonforandroid/bootstraps/lbry/build/templates/google-services.json
|
||||||
.gitsecret/keys/random_seed
|
.gitsecret/keys/random_seed
|
||||||
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
lbry-android.keystore:
|
lbry-android.keystore:
|
||||||
|
p4a/pythonforandroid/bootstraps/lbry/build/templates/google-services.json
|
||||||
|
|
|
@ -73,8 +73,8 @@ class FileDownloadButton extends React.PureComponent {
|
||||||
text={(isPlayable ? 'Play' : (isViewable ? 'View' : 'Download'))}
|
text={(isPlayable ? 'Play' : (isViewable ? 'View' : 'Download'))}
|
||||||
onLayout={onButtonLayout}
|
onLayout={onButtonLayout}
|
||||||
style={[style, fileDownloadButtonStyle.container]} onPress={() => {
|
style={[style, fileDownloadButtonStyle.container]} onPress={() => {
|
||||||
if (NativeModules.Mixpanel) {
|
if (NativeModules.Firebase) {
|
||||||
NativeModules.Mixpanel.track('Purchase Uri', { Uri: uri });
|
NativeModules.Firebase.track('purchase_uri', { uri: uri });
|
||||||
}
|
}
|
||||||
purchaseUri(uri, onStartDownloadFailed);
|
purchaseUri(uri, onStartDownloadFailed);
|
||||||
if (isPlayable && onPlay) {
|
if (isPlayable && onPlay) {
|
||||||
|
|
|
@ -36,8 +36,8 @@ class FileItem extends React.PureComponent {
|
||||||
navigateToFileUri = () => {
|
navigateToFileUri = () => {
|
||||||
const { navigation, uri } = this.props;
|
const { navigation, uri } = this.props;
|
||||||
const normalizedUri = normalizeURI(uri);
|
const normalizedUri = normalizeURI(uri);
|
||||||
if (NativeModules.Mixpanel) {
|
if (NativeModules.Firebase) {
|
||||||
NativeModules.Mixpanel.track('Discover Tap', { Uri: normalizeURI });
|
NativeModules.Firebase.track('explore_click', { uri: normalizedUri });
|
||||||
}
|
}
|
||||||
navigateToUri(navigation, normalizedUri);
|
navigateToUri(navigation, normalizedUri);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import SearchInput from './view';
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
search: search => {
|
search: search => {
|
||||||
if (NativeModules.Mixpanel) {
|
if (NativeModules.Firebase) {
|
||||||
NativeModules.Mixpanel.track('Search', { Query: search });
|
NativeModules.Firebase.track('search', { query: search });
|
||||||
}
|
}
|
||||||
return dispatch(doSearch(search));
|
return dispatch(doSearch(search));
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,8 +43,8 @@ import thunk from 'redux-thunk';
|
||||||
|
|
||||||
|
|
||||||
const globalExceptionHandler = (error, isFatal) => {
|
const globalExceptionHandler = (error, isFatal) => {
|
||||||
if (error && NativeModules.Mixpanel) {
|
if (error && NativeModules.Firebase) {
|
||||||
NativeModules.Mixpanel.logException(isFatal, error.message ? error.message : "No message", error);
|
NativeModules.Firebase.logException(isFatal, error.message ? error.message : "No message", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
setJSExceptionHandler(globalExceptionHandler, true);
|
setJSExceptionHandler(globalExceptionHandler, true);
|
||||||
|
|
|
@ -34,9 +34,9 @@ class DiscoverPage extends React.PureComponent {
|
||||||
AsyncStorage.getItem('firstLaunchSuspended').then(suspended => {
|
AsyncStorage.getItem('firstLaunchSuspended').then(suspended => {
|
||||||
AsyncStorage.removeItem('firstLaunchSuspended');
|
AsyncStorage.removeItem('firstLaunchSuspended');
|
||||||
const appSuspended = (suspended === 'true');
|
const appSuspended = (suspended === 'true');
|
||||||
if (NativeModules.Mixpanel) {
|
if (NativeModules.Firebase) {
|
||||||
NativeModules.Mixpanel.track('First Run Time', {
|
NativeModules.Firebase.track('first_run_time', {
|
||||||
'Total Seconds': delta, 'App Suspended': appSuspended
|
'total_seconds': delta, 'app_suspended': appSuspended
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -88,8 +88,8 @@ class FilePage extends React.PureComponent {
|
||||||
this.fetchFileInfo(this.props);
|
this.fetchFileInfo(this.props);
|
||||||
this.fetchCostInfo(this.props);
|
this.fetchCostInfo(this.props);
|
||||||
|
|
||||||
if (NativeModules.Mixpanel) {
|
if (NativeModules.Firebase) {
|
||||||
NativeModules.Mixpanel.track('Open File Page', { Uri: uri });
|
NativeModules.Firebase.track('open_file_page', { uri: uri });
|
||||||
}
|
}
|
||||||
if (NativeModules.UtilityModule) {
|
if (NativeModules.UtilityModule) {
|
||||||
NativeModules.UtilityModule.keepAwakeOn();
|
NativeModules.UtilityModule.keepAwakeOn();
|
||||||
|
@ -301,12 +301,12 @@ class FilePage extends React.PureComponent {
|
||||||
const { uri } = navigation.state.params;
|
const { uri } = navigation.state.params;
|
||||||
this.logFileView(uri, fileInfo, timeToStartMillis);
|
this.logFileView(uri, fileInfo, timeToStartMillis);
|
||||||
|
|
||||||
let payload = { 'Uri': uri };
|
let payload = { 'uri': uri };
|
||||||
if (!isNaN(timeToStart)) {
|
if (!isNaN(timeToStart)) {
|
||||||
payload['Time to Start (seconds)'] = timeToStart;
|
payload['time_to_start_seconds'] = timeToStart;
|
||||||
payload['Time to Start (ms)'] = timeToStartMillis;
|
payload['time_to_start_ms'] = timeToStartMillis;
|
||||||
}
|
}
|
||||||
NativeModules.Mixpanel.track('Play', payload);
|
NativeModules.Firebase.track('play', payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
onPlaybackFinished = () => {
|
onPlaybackFinished = () => {
|
||||||
|
|
|
@ -254,8 +254,8 @@ class SplashScreen extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (NativeModules.Mixpanel) {
|
if (NativeModules.Firebase) {
|
||||||
NativeModules.Mixpanel.track('App Launch', null);
|
NativeModules.Firebase.track('app_launch', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Linking.getInitialURL().then((url) => {
|
Linking.getInitialURL().then((url) => {
|
||||||
|
|
|
@ -148,7 +148,7 @@ android.react_src = ./app
|
||||||
|
|
||||||
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
||||||
# bootstrap)
|
# bootstrap)
|
||||||
android.gradle_dependencies = com.android.support:support-v4:27.1.1, com.android.support:support-media-compat:27.1.1, com.android.support:appcompat-v7:27.1.1, com.facebook.react:react-native:0.59.3, com.mixpanel.android:mixpanel-android:5+, com.google.android.gms:play-services-gcm:11.0.4+, com.facebook.fresco:fresco:1.9.0, com.facebook.fresco:animated-gif:1.9.0, com.squareup.picasso:picasso:2.71828
|
android.gradle_dependencies = com.android.support:support-v4:27.1.1, com.android.support:support-media-compat:27.1.1, com.android.support:appcompat-v7:27.1.1, com.facebook.react:react-native:0.59.3, com.google.android.gms:play-services-gcm:11.0.4+, com.facebook.fresco:fresco:1.9.0, com.facebook.fresco:animated-gif:1.9.0, com.squareup.picasso:picasso:2.71828, com.google.firebase:firebase-core:16.0.1
|
||||||
|
|
||||||
# (str) python-for-android branch to use, defaults to master
|
# (str) python-for-android branch to use, defaults to master
|
||||||
#p4a.branch = stable
|
#p4a.branch = stable
|
||||||
|
|
|
@ -148,7 +148,7 @@ android.react_src = ./app
|
||||||
|
|
||||||
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
||||||
# bootstrap)
|
# bootstrap)
|
||||||
android.gradle_dependencies = com.android.support:support-v4:27.1.1, com.android.support:support-media-compat:27.1.1, com.android.support:appcompat-v7:27.1.1, com.facebook.react:react-native:0.59.3, com.mixpanel.android:mixpanel-android:5+, com.google.android.gms:play-services-gcm:11.0.4+, com.facebook.fresco:fresco:1.9.0, com.facebook.fresco:animated-gif:1.9.0, com.squareup.picasso:picasso:2.71828
|
android.gradle_dependencies = com.android.support:support-v4:27.1.1, com.android.support:support-media-compat:27.1.1, com.android.support:appcompat-v7:27.1.1, com.facebook.react:react-native:0.59.3, com.google.android.gms:play-services-gcm:11.0.4+, com.facebook.fresco:fresco:1.9.0, com.facebook.fresco:animated-gif:1.9.0, com.squareup.picasso:picasso:2.71828, com.google.firebase:firebase-core:16.0.1
|
||||||
|
|
||||||
# (str) python-for-android branch to use, defaults to master
|
# (str) python-for-android branch to use, defaults to master
|
||||||
#p4a.branch = stable
|
#p4a.branch = stable
|
||||||
|
|
|
@ -148,7 +148,7 @@ android.react_src = ./app
|
||||||
|
|
||||||
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
||||||
# bootstrap)
|
# bootstrap)
|
||||||
android.gradle_dependencies = com.android.support:support-v4:27.1.1, com.android.support:support-media-compat:27.1.1, com.android.support:appcompat-v7:27.1.1, com.facebook.react:react-native:0.59.3, com.mixpanel.android:mixpanel-android:5+, com.google.android.gms:play-services-gcm:11.0.4+, com.facebook.fresco:fresco:1.9.0, com.facebook.fresco:animated-gif:1.9.0, com.squareup.picasso:picasso:2.71828
|
android.gradle_dependencies = com.android.support:support-v4:27.1.1, com.android.support:support-media-compat:27.1.1, com.android.support:appcompat-v7:27.1.1, com.facebook.react:react-native:0.59.3, com.google.android.gms:play-services-gcm:11.0.4+, com.facebook.fresco:fresco:1.9.0, com.facebook.fresco:animated-gif:1.9.0, com.squareup.picasso:picasso:2.71828, com.google.firebase:firebase-core:16.0.1
|
||||||
|
|
||||||
# (str) python-for-android branch to use, defaults to master
|
# (str) python-for-android branch to use, defaults to master
|
||||||
#p4a.branch = stable
|
#p4a.branch = stable
|
||||||
|
|
Binary file not shown.
|
@ -405,10 +405,10 @@ main.py that loads it.''')
|
||||||
android_api=android_api,
|
android_api=android_api,
|
||||||
build_tools_version=build_tools_version)
|
build_tools_version=build_tools_version)
|
||||||
|
|
||||||
render(
|
render('settings.gradle', 'settings.gradle')
|
||||||
'settings.tmpl.gradle',
|
|
||||||
'settings.gradle'
|
## google-services.json for firebase
|
||||||
)
|
render('google-services.json', 'google-services.json')
|
||||||
|
|
||||||
# copy icon drawables
|
# copy icon drawables
|
||||||
for folder in ('drawable-hdpi', 'drawable-mdpi', 'drawable-xhdpi', 'drawable-xxhdpi', 'drawable-xxxhdpi'):
|
for folder in ('drawable-hdpi', 'drawable-mdpi', 'drawable-xhdpi', 'drawable-xxhdpi', 'drawable-xxxhdpi'):
|
||||||
|
|
|
@ -6,6 +6,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.0.0'
|
classpath 'com.android.tools.build:gradle:3.0.0'
|
||||||
|
classpath 'com.google.gms:google-services:4.0.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,3 +113,6 @@ dependencies {
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
com.google.gms.googleservices.GoogleServicesPlugin.config.disableVersionCheck = true
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,80 @@
|
||||||
|
package io.lbry.browser.reactmodules;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||||
|
import com.facebook.react.bridge.ReactMethod;
|
||||||
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
|
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||||
|
|
||||||
|
import io.lbry.browser.BuildConfig;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
public class FirebaseModule extends ReactContextBaseJavaModule {
|
||||||
|
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
private FirebaseAnalytics firebaseAnalytics;
|
||||||
|
|
||||||
|
public FirebaseModule(ReactApplicationContext reactContext) {
|
||||||
|
super(reactContext);
|
||||||
|
this.context = reactContext;
|
||||||
|
this.firebaseAnalytics = FirebaseAnalytics.getInstance(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Firebase";
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void track(String name, ReadableMap payload) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
if (payload != null) {
|
||||||
|
HashMap<String, Object> payloadMap = payload.toHashMap();
|
||||||
|
for (Map.Entry<String, Object> entry : payloadMap.entrySet()) {
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value != null) {
|
||||||
|
bundle.putString(entry.getKey(), entry.getValue().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firebaseAnalytics != null) {
|
||||||
|
firebaseAnalytics.logEvent(name, bundle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void logException(boolean fatal, String message, ReadableMap payload) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
if (payload != null) {
|
||||||
|
HashMap<String, Object> payloadMap = payload.toHashMap();
|
||||||
|
for (Map.Entry<String, Object> entry : payloadMap.entrySet()) {
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value != null) {
|
||||||
|
bundle.putString(entry.getKey(), entry.getValue().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firebaseAnalytics != null) {
|
||||||
|
firebaseAnalytics.logEvent(fatal ? "exception" : "warning", bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatal) {
|
||||||
|
Toast.makeText(context,
|
||||||
|
"An application error occurred which has been automatically logged. " +
|
||||||
|
"If you keep seeing this message, please provide feedback to the LBRY " +
|
||||||
|
"team by emailing hello@lbry.io.",
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,87 +0,0 @@
|
||||||
package io.lbry.browser.reactmodules;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
|
||||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
||||||
import com.facebook.react.bridge.ReactMethod;
|
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
|
||||||
|
|
||||||
import com.mixpanel.android.mpmetrics.MixpanelAPI;
|
|
||||||
|
|
||||||
import io.lbry.browser.BuildConfig;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
public class MixpanelModule extends ReactContextBaseJavaModule {
|
|
||||||
|
|
||||||
private static final String MIXPANEL_TOKEN = BuildConfig.DEBUG ?
|
|
||||||
"bc1630b8be64c5dfaa4700b3a62969f3" /* Dev Testing */ :
|
|
||||||
"93b81fb957cb0ddcd3198c10853a6a95"; /* Production */
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
private MixpanelAPI mixpanel;
|
|
||||||
|
|
||||||
public MixpanelModule(ReactApplicationContext reactContext) {
|
|
||||||
super(reactContext);
|
|
||||||
this.context = reactContext;
|
|
||||||
this.mixpanel = MixpanelAPI.getInstance(this.context, MIXPANEL_TOKEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Mixpanel";
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactMethod
|
|
||||||
public void track(String name, ReadableMap payload) {
|
|
||||||
JSONObject props = new JSONObject();
|
|
||||||
try {
|
|
||||||
if (payload != null) {
|
|
||||||
HashMap<String, Object> payloadMap = payload.toHashMap();
|
|
||||||
for (Map.Entry<String, Object> entry : payloadMap.entrySet()) {
|
|
||||||
props.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// Cannot use props. Stick with empty props.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mixpanel != null) {
|
|
||||||
mixpanel.track(name, props);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactMethod
|
|
||||||
public void logException(boolean fatal, String message, ReadableMap payload) {
|
|
||||||
JSONObject props = new JSONObject();
|
|
||||||
try {
|
|
||||||
props.put("Message", message);
|
|
||||||
if (payload != null) {
|
|
||||||
HashMap<String, Object> payloadMap = payload.toHashMap();
|
|
||||||
for (Map.Entry<String, Object> entry : payloadMap.entrySet()) {
|
|
||||||
props.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// Cannot use props. Stick with empty props.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mixpanel != null) {
|
|
||||||
mixpanel.track(fatal ? "Exception" : "Warning", props);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fatal) {
|
|
||||||
Toast.makeText(context,
|
|
||||||
"An application error occurred which has been automatically logged. " +
|
|
||||||
"If you keep seeing this message, please provide feedback to the LBRY " +
|
|
||||||
"team by emailing hello@lbry.io.",
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,7 +9,7 @@ import io.lbry.browser.reactmodules.BackgroundMediaModule;
|
||||||
import io.lbry.browser.reactmodules.DaemonServiceControlModule;
|
import io.lbry.browser.reactmodules.DaemonServiceControlModule;
|
||||||
import io.lbry.browser.reactmodules.DownloadManagerModule;
|
import io.lbry.browser.reactmodules.DownloadManagerModule;
|
||||||
import io.lbry.browser.reactmodules.FirstRunModule;
|
import io.lbry.browser.reactmodules.FirstRunModule;
|
||||||
import io.lbry.browser.reactmodules.MixpanelModule;
|
import io.lbry.browser.reactmodules.FirebaseModule;
|
||||||
import io.lbry.browser.reactmodules.ScreenOrientationModule;
|
import io.lbry.browser.reactmodules.ScreenOrientationModule;
|
||||||
import io.lbry.browser.reactmodules.VersionInfoModule;
|
import io.lbry.browser.reactmodules.VersionInfoModule;
|
||||||
import io.lbry.browser.reactmodules.UtilityModule;;
|
import io.lbry.browser.reactmodules.UtilityModule;;
|
||||||
|
@ -32,7 +32,7 @@ public class LbryReactPackage implements ReactPackage {
|
||||||
modules.add(new DaemonServiceControlModule(reactContext));
|
modules.add(new DaemonServiceControlModule(reactContext));
|
||||||
modules.add(new DownloadManagerModule(reactContext));
|
modules.add(new DownloadManagerModule(reactContext));
|
||||||
modules.add(new FirstRunModule(reactContext));
|
modules.add(new FirstRunModule(reactContext));
|
||||||
modules.add(new MixpanelModule(reactContext));
|
modules.add(new FirebaseModule(reactContext));
|
||||||
modules.add(new ScreenOrientationModule(reactContext));
|
modules.add(new ScreenOrientationModule(reactContext));
|
||||||
modules.add(new UtilityModule(reactContext));
|
modules.add(new UtilityModule(reactContext));
|
||||||
modules.add(new VersionInfoModule(reactContext));
|
modules.add(new VersionInfoModule(reactContext));
|
||||||
|
|
Loading…
Reference in a new issue