Replace Mixpanel with Firebase (Google) analytics #535
19 changed files with 122 additions and 117 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -10,4 +10,6 @@ src/main/assets/index.android.bundle.meta
|
|||
.vagrant
|
||||
|
||||
lbry-android.keystore
|
||||
p4a/pythonforandroid/bootstraps/lbry/build/templates/google-services.json
|
||||
.gitsecret/keys/random_seed
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
lbry-android.keystore:
|
||||
p4a/pythonforandroid/bootstraps/lbry/build/templates/google-services.json
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
"dependencies": {
|
||||
"base-64": "^0.1.0",
|
||||
"@expo/vector-icons": "^8.1.0",
|
||||
"lbry-redux": "lbryio/lbry-redux#claim-search-fix",
|
||||
"lbryinc": "lbryio/lbryinc#sdk-0.36-changes",
|
||||
"lbry-redux": "lbryio/lbry-redux",
|
||||
"lbryinc": "lbryio/lbryinc",
|
||||
"lodash": ">=4.17.11",
|
||||
"merge": ">=1.2.1",
|
||||
"moment": "^2.22.1",
|
||||
|
|
|
@ -73,8 +73,8 @@ class FileDownloadButton extends React.PureComponent {
|
|||
text={(isPlayable ? 'Play' : (isViewable ? 'View' : 'Download'))}
|
||||
onLayout={onButtonLayout}
|
||||
style={[style, fileDownloadButtonStyle.container]} onPress={() => {
|
||||
if (NativeModules.Mixpanel) {
|
||||
NativeModules.Mixpanel.track('Purchase Uri', { Uri: uri });
|
||||
if (NativeModules.Firebase) {
|
||||
NativeModules.Firebase.track('purchase_uri', { uri: uri });
|
||||
}
|
||||
purchaseUri(uri, onStartDownloadFailed);
|
||||
if (isPlayable && onPlay) {
|
||||
|
|
|
@ -36,8 +36,8 @@ class FileItem extends React.PureComponent {
|
|||
navigateToFileUri = () => {
|
||||
const { navigation, uri } = this.props;
|
||||
const normalizedUri = normalizeURI(uri);
|
||||
if (NativeModules.Mixpanel) {
|
||||
NativeModules.Mixpanel.track('Discover Tap', { Uri: normalizeURI });
|
||||
if (NativeModules.Firebase) {
|
||||
NativeModules.Firebase.track('explore_click', { uri: normalizedUri });
|
||||
}
|
||||
navigateToUri(navigation, normalizedUri);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import SearchInput from './view';
|
|||
|
||||
const perform = dispatch => ({
|
||||
search: search => {
|
||||
if (NativeModules.Mixpanel) {
|
||||
NativeModules.Mixpanel.track('Search', { Query: search });
|
||||
if (NativeModules.Firebase) {
|
||||
NativeModules.Firebase.track('search', { query: search });
|
||||
}
|
||||
return dispatch(doSearch(search));
|
||||
},
|
||||
|
|
|
@ -43,8 +43,8 @@ import thunk from 'redux-thunk';
|
|||
|
||||
|
||||
const globalExceptionHandler = (error, isFatal) => {
|
||||
if (error && NativeModules.Mixpanel) {
|
||||
NativeModules.Mixpanel.logException(isFatal, error.message ? error.message : "No message", error);
|
||||
if (error && NativeModules.Firebase) {
|
||||
NativeModules.Firebase.logException(isFatal, error.message ? error.message : "No message", error);
|
||||
}
|
||||
};
|
||||
setJSExceptionHandler(globalExceptionHandler, true);
|
||||
|
|
|
@ -34,9 +34,9 @@ class DiscoverPage extends React.PureComponent {
|
|||
AsyncStorage.getItem('firstLaunchSuspended').then(suspended => {
|
||||
AsyncStorage.removeItem('firstLaunchSuspended');
|
||||
const appSuspended = (suspended === 'true');
|
||||
if (NativeModules.Mixpanel) {
|
||||
NativeModules.Mixpanel.track('First Run Time', {
|
||||
'Total Seconds': delta, 'App Suspended': appSuspended
|
||||
if (NativeModules.Firebase) {
|
||||
NativeModules.Firebase.track('first_run_time', {
|
||||
'total_seconds': delta, 'app_suspended': appSuspended
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -88,8 +88,8 @@ class FilePage extends React.PureComponent {
|
|||
this.fetchFileInfo(this.props);
|
||||
this.fetchCostInfo(this.props);
|
||||
|
||||
if (NativeModules.Mixpanel) {
|
||||
NativeModules.Mixpanel.track('Open File Page', { Uri: uri });
|
||||
if (NativeModules.Firebase) {
|
||||
NativeModules.Firebase.track('open_file_page', { uri: uri });
|
||||
}
|
||||
if (NativeModules.UtilityModule) {
|
||||
NativeModules.UtilityModule.keepAwakeOn();
|
||||
|
@ -301,12 +301,12 @@ class FilePage extends React.PureComponent {
|
|||
const { uri } = navigation.state.params;
|
||||
this.logFileView(uri, fileInfo, timeToStartMillis);
|
||||
|
||||
let payload = { 'Uri': uri };
|
||||
let payload = { 'uri': uri };
|
||||
if (!isNaN(timeToStart)) {
|
||||
payload['Time to Start (seconds)'] = timeToStart;
|
||||
payload['Time to Start (ms)'] = timeToStartMillis;
|
||||
payload['time_to_start_seconds'] = timeToStart;
|
||||
payload['time_to_start_ms'] = timeToStartMillis;
|
||||
}
|
||||
NativeModules.Mixpanel.track('Play', payload);
|
||||
NativeModules.Firebase.track('play', payload);
|
||||
}
|
||||
|
||||
onPlaybackFinished = () => {
|
||||
|
|
|
@ -254,8 +254,8 @@ class SplashScreen extends React.PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (NativeModules.Mixpanel) {
|
||||
NativeModules.Mixpanel.track('App Launch', null);
|
||||
if (NativeModules.Firebase) {
|
||||
NativeModules.Firebase.track('app_launch', null);
|
||||
}
|
||||
|
||||
Linking.getInitialURL().then((url) => {
|
||||
|
|
|
@ -148,7 +148,7 @@ android.react_src = ./app
|
|||
|
||||
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
||||
# 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
|
||||
#p4a.branch = stable
|
||||
|
|
|
@ -148,7 +148,7 @@ android.react_src = ./app
|
|||
|
||||
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
||||
# 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
|
||||
#p4a.branch = stable
|
||||
|
|
|
@ -148,7 +148,7 @@ android.react_src = ./app
|
|||
|
||||
# (list) Gradle dependencies to add (currently works only with sdl2_gradle
|
||||
# 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
|
||||
#p4a.branch = stable
|
||||
|
|
|
@ -405,10 +405,10 @@ main.py that loads it.''')
|
|||
android_api=android_api,
|
||||
build_tools_version=build_tools_version)
|
||||
|
||||
render(
|
||||
'settings.tmpl.gradle',
|
||||
'settings.gradle'
|
||||
)
|
||||
render('settings.gradle', 'settings.gradle')
|
||||
|
||||
## google-services.json for firebase
|
||||
render('google-services.json', 'google-services.json')
|
||||
|
||||
# copy icon drawables
|
||||
for folder in ('drawable-hdpi', 'drawable-mdpi', 'drawable-xhdpi', 'drawable-xxhdpi', 'drawable-xxxhdpi'):
|
||||
|
|
|
@ -6,6 +6,7 @@ buildscript {
|
|||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.0'
|
||||
classpath 'com.google.gms:google-services:4.0.1'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +42,11 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility 1.8
|
||||
targetCompatibility 1.8
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
jumboMode true
|
||||
}
|
||||
|
@ -107,3 +113,6 @@ dependencies {
|
|||
{%- endfor %}
|
||||
{%- endif %}
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
com.google.gms.googleservices.GoogleServicesPlugin.config.disableVersionCheck = true
|
||||
|
|
|
@ -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.DownloadManagerModule;
|
||||
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.VersionInfoModule;
|
||||
import io.lbry.browser.reactmodules.UtilityModule;;
|
||||
|
@ -32,7 +32,7 @@ public class LbryReactPackage implements ReactPackage {
|
|||
modules.add(new DaemonServiceControlModule(reactContext));
|
||||
modules.add(new DownloadManagerModule(reactContext));
|
||||
modules.add(new FirstRunModule(reactContext));
|
||||
modules.add(new MixpanelModule(reactContext));
|
||||
modules.add(new FirebaseModule(reactContext));
|
||||
modules.add(new ScreenOrientationModule(reactContext));
|
||||
modules.add(new UtilityModule(reactContext));
|
||||
modules.add(new VersionInfoModule(reactContext));
|
||||
|
|
Loading…
Reference in a new issue