Use Crashlytics instead of ACRA
This commit is contained in:
parent
152982093d
commit
acbb3ec678
13 changed files with 56 additions and 157 deletions
|
@ -1,7 +1,5 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
def acra = new Properties()
|
||||
acra.load(new FileInputStream("app/acra.properties"))
|
||||
apply plugin: 'io.fabric'
|
||||
|
||||
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||
def keystoreProperties = new Properties()
|
||||
|
@ -28,12 +26,10 @@ android {
|
|||
applicationId "com.wbrawner.simplemarkdown"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 28
|
||||
multiDexEnabled true
|
||||
versionCode 16
|
||||
versionName "0.6.0-beta1"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
buildConfigField "String", "ACRA_URL", "\"${acra.getProperty("url")}\""
|
||||
buildConfigField "String", "ACRA_USER", "\"${acra.getProperty("user")}\""
|
||||
buildConfigField "String", "ACRA_PASS", "\"${acra.getProperty("pass")}\""
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
|
@ -81,7 +77,7 @@ dependencies {
|
|||
annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.robolectric:robolectric:4.1'
|
||||
testImplementation 'org.robolectric:robolectric:4.2'
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
|
@ -101,10 +97,10 @@ dependencies {
|
|||
implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.6'
|
||||
implementation "ch.acra:acra-http:$acraVersion"
|
||||
implementation 'com.google.firebase:firebase-core:16.0.7'
|
||||
implementation 'com.google.firebase:firebase-ads:17.1.3'
|
||||
implementation 'com.google.firebase:firebase-core:16.0.8'
|
||||
implementation 'com.google.firebase:firebase-ads:17.2.0'
|
||||
implementation 'com.android.billingclient:billing:1.2'
|
||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
|
||||
samsungImplementation project(":IAP5Helper")
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,10 @@
|
|||
android:name=".view.activity.ExplorerActivity"
|
||||
android:label="@string/title_activity_explorer"
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
|
||||
<meta-data
|
||||
android:name="firebase_crashlytics_collection_enabled"
|
||||
android:value="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -1,61 +1,13 @@
|
|||
## Privacy Policy
|
||||
|
||||
First and foremost, Simple Markdown DOES NOT collect any personally identifiable information. The internet access permission is requested primarily for retrieving images from the internet in case you embed them in your markdown, but it also allows me to send automated error and crash reports to myself whenever the app runs into an issue. These error reports are powered by [ACRA](https://github.com/ACRA/acra), which is an open source error reporting solution, and are sent to a private server that only I have access to. These error reports are used exclusively for fixing problems that occur while you're using the app, and contain only the bare minimum information that I need to be able to resolve the issue. The information sent may include the following:
|
||||
|
||||
- the version of Android your device is running (e.g. 7.1)
|
||||
- details about the version of SimpleMarkdown that you are using (Google Play version, Samsung Galaxy Apps version, FDroid version, version number, etc)
|
||||
- the app identifier (com.wbrawner.simplemarkdown)
|
||||
- your device's manufacturer (Samsung, Huawei, LG, etc)
|
||||
- your device's model (Galaxy S8, Mate 10 pro, G7, etc)
|
||||
- your device's configuration at app start and at the moment of the error (the configuration tells me things like if you had the keyboard open, and if you were using the app in landscape or portrait mode. See the end of this privacy policy for a sample of that this might look like.)
|
||||
- an estimation of the amount of available memory your device has (7353192448)
|
||||
- an estimation of the amount of total memory your device has (55540875264)
|
||||
- a stacktrace of the error (a stacktrace tells me which part of my code caused the error, what kind of error it was, and which parts of the code ran up to that error. See the end of this privacy policy for a sample of what this might look like.)
|
||||
- any custom settings you have set within SimpleMarkdown (your default launch screen, default file directory, etc. Note that this does NOT include settings specific to your device, like whether or not you have WiFi enabled for example)
|
||||
- details about which thread the error occurred on (e.g. main, file handling, network)
|
||||
- the time and date you started the app
|
||||
- the time and date the error occurred
|
||||
|
||||
This information is the only information that I collect, and it's strictly used for finding and fixing issues in the code as quickly as possible. If you don't feel comfortable with this however, you are able to opt-out from the settings menu. Should you choose to opt-out of automated error reports, I would very much appreciate it if you could contact me when you run into an issue either by email: [support@wbrawner.com](mailto:support@wbrawner.com) or by submitting an issue via the [GitHub page](https://github.com/wbrawner/SimpleMarkdown).
|
||||
|
||||
### Sample data
|
||||
|
||||
A sample configuration:
|
||||
|
||||
```
|
||||
locale=fr_FR
|
||||
hardKeyboardHidden=HARDKEYBOARDHIDDEN_YES
|
||||
keyboard=KEYBOARD_NOKEYS
|
||||
keyboardHidden=KEYBOARDHIDDEN_NO
|
||||
fontScale=1.0
|
||||
mcc=208
|
||||
mnc=10
|
||||
navigation=NAVIGATION_TRACKBALL
|
||||
navigationHidden=NAVIGATIONHIDDEN_NO
|
||||
orientation=ORIENTATION_PORTRAIT
|
||||
screenLayout=SCREENLAYOUT_SIZE_NORMAL+SCREENLAYOUT_LONG_YES
|
||||
seq=117
|
||||
touchscreen=TOUCHSCREEN_FINGER
|
||||
uiMode=UI_MODE_TYPE_NORMAL+UI_MODE_NIGHT_NO
|
||||
userSetLocale=false
|
||||
```
|
||||
|
||||
A sample stacktrace:
|
||||
|
||||
```
|
||||
java.io.IOException: No such file or directory
|
||||
at java.io.UnixFileSystem.createFileExclusively0(UnixFileSystem.java)
|
||||
at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:280)
|
||||
at java.io.File.createNewFile(File.java:948)
|
||||
at com.wbrawner.simplemarkdown.model.MarkdownFile.save(MarkdownFile.java:152)
|
||||
at com.wbrawner.simplemarkdown.presentation.MarkdownPresenterImpl.saveMarkdown(MarkdownPresenterImpl.java:120)
|
||||
at com.wbrawner.simplemarkdown.presentation.MarkdownPresenterImpl.lambda$saveMarkdown$2$MarkdownPresenterImpl(MarkdownPresenterImpl.java:120)
|
||||
at com.wbrawner.simplemarkdown.presentation.MarkdownPresenterImpl$$Lambda$2.run(MarkdownPresenterImpl.java)
|
||||
at android.os.Handler.handleCallback(Handler.java:751)
|
||||
at android.os.Handler.dispatchMessage(Handler.java:95)
|
||||
at android.os.Looper.loop(Looper.java:154)
|
||||
at android.app.ActivityThread.main(ActivityThread.java:6121)
|
||||
at java.lang.reflect.Method.invoke(Method.java)
|
||||
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
|
||||
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
|
||||
```
|
||||
First and foremost, Simple Markdown DOES NOT collect any personally identifiable information. The
|
||||
internet access permission is requested primarily for retrieving images from the internet in
|
||||
case you embed them in your markdown, but it also allows me to send automated error and crash
|
||||
reports to myself whenever the app runs into an issue. These error reports are powered by
|
||||
[Firebase Crashlytics] (https://firebase.google.com/docs/crashlytics/), which is a free error
|
||||
reporting solution provided by Google. These error reports are used exclusively for fixing
|
||||
problems that occur while you're using the app, along with some analytics info like how long you
|
||||
use the app for, how often, and which features of the app you use. This helps me to determine
|
||||
how to spend my very limited time on building out new features. I'll have to defer to [Google's
|
||||
Privacy Policy](https://policies.google.com/privacy) to explain how they handle the data. As
|
||||
for me, I don't knowingly or willingly sell or trade your data.
|
||||
|
|
|
@ -1,64 +1,7 @@
|
|||
package com.wbrawner.simplemarkdown;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import org.acra.annotation.AcraCore;
|
||||
import org.acra.annotation.AcraHttpSender;
|
||||
import org.acra.data.StringFormat;
|
||||
import org.acra.sender.HttpSender;
|
||||
|
||||
import static com.wbrawner.simplemarkdown.BuildConfig.ACRA_PASS;
|
||||
import static com.wbrawner.simplemarkdown.BuildConfig.ACRA_URL;
|
||||
import static com.wbrawner.simplemarkdown.BuildConfig.ACRA_USER;
|
||||
import static org.acra.ReportField.ANDROID_VERSION;
|
||||
import static org.acra.ReportField.APP_VERSION_CODE;
|
||||
import static org.acra.ReportField.APP_VERSION_NAME;
|
||||
import static org.acra.ReportField.AVAILABLE_MEM_SIZE;
|
||||
import static org.acra.ReportField.BRAND;
|
||||
import static org.acra.ReportField.BUILD_CONFIG;
|
||||
import static org.acra.ReportField.CRASH_CONFIGURATION;
|
||||
import static org.acra.ReportField.CUSTOM_DATA;
|
||||
import static org.acra.ReportField.INITIAL_CONFIGURATION;
|
||||
import static org.acra.ReportField.PACKAGE_NAME;
|
||||
import static org.acra.ReportField.PHONE_MODEL;
|
||||
import static org.acra.ReportField.SHARED_PREFERENCES;
|
||||
import static org.acra.ReportField.STACK_TRACE;
|
||||
import static org.acra.ReportField.STACK_TRACE_HASH;
|
||||
import static org.acra.ReportField.THREAD_DETAILS;
|
||||
import static org.acra.ReportField.TOTAL_MEM_SIZE;
|
||||
import static org.acra.ReportField.USER_APP_START_DATE;
|
||||
import static org.acra.ReportField.USER_CRASH_DATE;
|
||||
|
||||
@AcraCore(
|
||||
buildConfigClass = BuildConfig.class,
|
||||
reportContent = {
|
||||
ANDROID_VERSION,
|
||||
APP_VERSION_CODE,
|
||||
APP_VERSION_NAME,
|
||||
AVAILABLE_MEM_SIZE,
|
||||
BRAND,
|
||||
BUILD_CONFIG,
|
||||
CRASH_CONFIGURATION,
|
||||
CUSTOM_DATA, // Not currently used, but might be useful in the future
|
||||
INITIAL_CONFIGURATION,
|
||||
PACKAGE_NAME,
|
||||
PHONE_MODEL,
|
||||
SHARED_PREFERENCES,
|
||||
STACK_TRACE,
|
||||
STACK_TRACE_HASH,
|
||||
THREAD_DETAILS,
|
||||
TOTAL_MEM_SIZE,
|
||||
USER_APP_START_DATE,
|
||||
USER_CRASH_DATE,
|
||||
},
|
||||
reportFormat = StringFormat.JSON
|
||||
)
|
||||
@AcraHttpSender(uri = ACRA_URL,
|
||||
basicAuthLogin = ACRA_USER,
|
||||
basicAuthPassword = ACRA_PASS,
|
||||
httpMethod = HttpSender.Method.POST)
|
||||
public class MarkdownApplication extends Application {
|
||||
|
||||
private AppComponent component;
|
||||
|
@ -74,10 +17,4 @@ public class MarkdownApplication extends Application {
|
|||
public AppComponent getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
ACRA.init(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package com.wbrawner.simplemarkdown.model;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.wbrawner.simplemarkdown.utility.Utils;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -112,7 +111,7 @@ public class MarkdownFile {
|
|||
this.content = sb.toString();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
return false;
|
||||
} finally {
|
||||
Utils.closeQuietly(reader);
|
||||
|
@ -133,7 +132,7 @@ public class MarkdownFile {
|
|||
this.path = markdownFile.getParentFile().getAbsolutePath();
|
||||
return load(new FileInputStream(markdownFile));
|
||||
} catch (FileNotFoundException e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +158,7 @@ public class MarkdownFile {
|
|||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -175,14 +174,14 @@ public class MarkdownFile {
|
|||
);
|
||||
writer.write(this.content);
|
||||
} catch (IOException e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
return false;
|
||||
} finally {
|
||||
if (writer != null) {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
// closing the reader failed
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,13 +12,12 @@ import com.android.billingclient.api.BillingClientStateListener;
|
|||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener;
|
||||
import com.commonsware.cwac.anddown.AndDown;
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.wbrawner.simplemarkdown.model.MarkdownFile;
|
||||
import com.wbrawner.simplemarkdown.utility.Utils;
|
||||
import com.wbrawner.simplemarkdown.view.MarkdownEditView;
|
||||
import com.wbrawner.simplemarkdown.view.MarkdownPreviewView;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -75,7 +74,7 @@ public class MarkdownPresenterImpl
|
|||
InputStream in = new FileInputStream(file);
|
||||
loadMarkdown(file.getName(), in);
|
||||
} catch (FileNotFoundException e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,7 +248,7 @@ public class MarkdownPresenterImpl
|
|||
}
|
||||
loadMarkdown(fileName, in);
|
||||
} catch (Exception e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
MarkdownEditView currentEditView = editView;
|
||||
if (currentEditView != null) {
|
||||
currentEditView.onFileLoaded(false);
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.os.HandlerThread;
|
|||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
|
@ -104,7 +104,7 @@ public class Utils {
|
|||
HandlerThread handlerThread = new HandlerThread(name);
|
||||
handlerThread.start();
|
||||
handlerThread.setUncaughtExceptionHandler((t, e) -> {
|
||||
ACRA.getErrorReporter().handleException(e);
|
||||
Crashlytics.logException(e);
|
||||
t.interrupt();
|
||||
});
|
||||
return new Handler(handlerThread.getLooper());
|
||||
|
|
|
@ -15,12 +15,11 @@ import android.widget.EditText;
|
|||
import android.widget.ListView;
|
||||
import android.widget.SimpleAdapter;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.wbrawner.simplemarkdown.R;
|
||||
import com.wbrawner.simplemarkdown.utility.Constants;
|
||||
import com.wbrawner.simplemarkdown.utility.Utils;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -119,7 +118,7 @@ public class ExplorerActivity extends AppCompatActivity {
|
|||
try {
|
||||
sdcardSelected = filePath.get().contains(mounts[1].getAbsolutePath());
|
||||
} catch (NullPointerException e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
updateListView();
|
||||
menu.findItem(R.id.action_use_sdcard).setVisible(false);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.google.ads.mediation.admob.AdMobAdapter;
|
||||
import com.google.android.gms.ads.AdListener;
|
||||
import com.google.android.gms.ads.AdRequest;
|
||||
|
@ -29,8 +30,6 @@ import com.wbrawner.simplemarkdown.utility.Utils;
|
|||
import com.wbrawner.simplemarkdown.view.DisableableViewPager;
|
||||
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
@ -89,7 +88,7 @@ public class MainActivity extends AppCompatActivity
|
|||
@Override
|
||||
public void onAdFailedToLoad(int i) {
|
||||
super.onAdFailedToLoad(i);
|
||||
ACRA.getErrorReporter().handleException(new RuntimeException("Failed to load ads: " + i), false);
|
||||
Crashlytics.logException(new RuntimeException("Failed to load ads: " + i));
|
||||
}
|
||||
});
|
||||
adView.loadAd(adRequest);
|
||||
|
@ -200,7 +199,7 @@ public class MainActivity extends AppCompatActivity
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
ACRA.getErrorReporter().handleException(e, false);
|
||||
Crashlytics.logException(e);
|
||||
Toast.makeText(MainActivity.this, R.string.file_load_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,14 @@ import android.view.MenuItem;
|
|||
import android.webkit.WebView;
|
||||
|
||||
import com.wbrawner.simplemarkdown.R;
|
||||
import com.wbrawner.simplemarkdown.view.fragment.PreviewFragment;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class MarkdownInfoActivity extends AppCompatActivity {
|
||||
public static String FORMAT_CSS = "<style>" +
|
||||
"%s" +
|
||||
"</style>";
|
||||
|
||||
@BindView(R.id.info_webview)
|
||||
WebView infoWebview;
|
||||
|
@ -35,7 +37,9 @@ public class MarkdownInfoActivity extends AppCompatActivity {
|
|||
setTitle(intent.getStringExtra("title"));
|
||||
infoWebview.loadDataWithBaseURL(
|
||||
null,
|
||||
getString(R.string.pref_custom_css_default) + intent.getStringExtra("html"),
|
||||
String.format(FORMAT_CSS,
|
||||
getString(R.string.pref_custom_css_default)
|
||||
) + intent.getStringExtra("html"),
|
||||
"text/html",
|
||||
"UTF-8",
|
||||
null
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.preference.PreferenceManager;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.wbrawner.simplemarkdown.MarkdownApplication;
|
||||
import com.wbrawner.simplemarkdown.R;
|
||||
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter;
|
||||
|
@ -15,6 +16,8 @@ import com.wbrawner.simplemarkdown.utility.Utils;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
|
||||
@Inject
|
||||
|
@ -23,6 +26,10 @@ public class SplashActivity extends AppCompatActivity {
|
|||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if (sharedPreferences.getBoolean(getString(R.string.error_reports_enabled), true)) {
|
||||
Fabric.with(this, new Crashlytics());
|
||||
}
|
||||
((MarkdownApplication) getApplication()).getComponent().inject(this);
|
||||
|
||||
String defaultName = Utils.getDefaultFileName(this);
|
||||
|
@ -34,7 +41,6 @@ public class SplashActivity extends AppCompatActivity {
|
|||
presenter.setFileName(defaultName);
|
||||
}
|
||||
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String defaultRootDir =
|
||||
sharedPreferences.getString(Constants.KEY_DOCS_PATH, Utils.getDocsPath(this));
|
||||
presenter.setRootDir(defaultRootDir);
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<string name="action_select">Select</string>
|
||||
<string name="directory_up">\u2191 Go up</string>
|
||||
<string name="action_privacy">Privacy</string>
|
||||
<string name="error_reports_enabled">acra.enable</string>
|
||||
<string name="error_reports_enabled">crashlytics.enable</string>
|
||||
<string name="pref_title_error_reports">Enable automated error reports</string>
|
||||
<string name="pref_error_reports_off">Error reports will not be sent</string>
|
||||
<string name="pref_error_reports_on">Error reports will be sent</string>
|
||||
|
|
|
@ -4,10 +4,14 @@ buildscript {
|
|||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
maven {
|
||||
url 'https://maven.fabric.io/public'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.3.1'
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.google.gms:google-services:4.2.0'
|
||||
classpath 'io.fabric.tools:gradle:1.26.1'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue