linkedin.com/in/cosminstefan
cosmin@greenerpastures.ro
// build.gradle (app)
android {
...
buildTypes {
debug {
...
firebaseCrashlytics {
// If you don't need crash reporting for your debug build,
// you can speed up your build by disabling mapping file uploading.
mappingFileUploadEnabled false
}
}
}
}
// build.gradle (app)
android {
...
buildTypes {
debug {
...
firebaseCrashlytics {
// If you don't need crash reporting for your debug build,
// you can speed up your build by disabling mapping file uploading.
mappingFileUploadEnabled false
}
}
}
}
<!-- AndroidManifest.xml -->
<meta-data android:name="firebase_crashlytics_collection_enabled"
android:value="${firebaseCrashlyticsCollectionEnabled}" />
// build.gradle (app)
android {
...
buildTypes {
debug {
...
firebaseCrashlytics {
// If you don't need crash reporting for your debug build,
// you can speed up your build by disabling mapping file uploading.
mappingFileUploadEnabled false
// Or you can opt out of reporting completely
// (Make sure you enable the flag on release builds)
manifestPlaceholders.firebaseCrashlyticsCollectionEnabled = false
}
}
}
}
<!-- AndroidManifest.xml -->
<meta-data android:name="firebase_crashlytics_collection_enabled"
android:value="${firebaseCrashlyticsCollectionEnabled}" />
// build.gradle (app)
android {
...
productFlavors {
staging {
...
// The following configuration limits the "staging" flavor to using
// EN gresources and xxxhdpi screen-density resources.
resConfigs "en", "xxxhdpi"
}
...
}
}
./gradlew clean
./gradlew --profile --offline --rerun-tasks assembleFlavorDebug
// build.gradle (root)
ext {
...
// Timber - https://github.com/JakeWharton/timber
timber = "com.jakewharton.timber:timber:4.7.1"
}
// build.gradle (root)
ext {
...
// Timber - https://github.com/JakeWharton/timber
timber = "com.jakewharton.timber:timber:4.7.1"
// Retrofit - https://github.com/square/retrofit/releases
retrofitVersion = '2.8.1'
retrofit = [
core: "com.squareup.retrofit2:retrofit:$retrofitVersion",
gson: "com.squareup.retrofit2:converter-gson:$retrofitVersion"
]
}
// build.gradle (root)
ext {
...
// Timber - https://github.com/JakeWharton/timber
timber = "com.jakewharton.timber:timber:4.7.1"
// Retrofit - https://github.com/square/retrofit/releases
retrofitVersion = '2.8.1'
retrofit = [
core: "com.squareup.retrofit2:retrofit:$retrofitVersion",
gson: "com.squareup.retrofit2:converter-gson:$retrofitVersion"
]
// AndroidX - https://developer.android.com/jetpack/androidx/releases/
androidWorkManagerVersion = '2.3.4'
androidx = [
appcompat : "androidx.appcompat:appcompat:1.2.0",
fragment : "androidx.fragment:fragment-ktx:1.2.5",
workManager : [
runtime : "androidx.work:work-runtime:$androidWorkManagerVersion",
rx : "androidx.work:work-rxjava2:$androidWorkManagerVersion",
],
]
}
// build.gradle (app)
dependencies {
...
// Timber
implementation timber
// Retrofit
implementation retrofit.core
implementation retrofit.gson
// AndroidX
implementation androidx.fragment
implementation androidx.workManager.runtime
implementation androidx.workManager.rx
}
// build.gradle (app)
dependencies {
...
// Declare the dependencies for the desired Firebase products
// by specifying versions
implementation 'com.google.firebase:firebase-auth:19.4.0'
implementation 'com.google.firebase:firebase-firestore-ktx:21.7.1'
implementation 'com.google.firebase:firebase-storage-ktx:19.2.0'
}
// build.gradle (app)
dependencies {
...
// Import the BoM for the Firebase platform
implementation platform('com.google.firebase:firebase-bom:25.12.0')
// Declare the dependencies for the desired Firebase products
// without specifying versions
implementation 'com.google.firebase:firebase-auth'
implementation 'com.google.firebase:firebase-firestore-ktx'
}
// build.gradle (app)
android {
...
signingConfigs {
release {
// DON'T DO THIS!!
storeFile file("myapp.keystore")
storePassword "password123"
keyAlias "thekey"
keyPassword "password789"
}
}
}
// gradle.properties
KEYSTORE_PASSWORD=password123
KEY_PASSWORD=password789
// build.gradle (app)
android {
...
signingConfigs {
release {
try {
storeFile file("myapp.keystore")
storePassword KEYSTORE_PASSWORD
keyAlias "thekey"
keyPassword KEY_PASSWORD
}
catch (ex) {
throw new InvalidUserDataException("Missing in gradle.properties")
}
}
}
}
Mistakes are proof that you're trying!
// Application.kt
fun onCreate() {
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
// or .detectAll() for all detectable problems
.penaltyLog()
.build())
StrictMode.setVmPolicy(VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build())
}
super.onCreate()
...
}
Life's too short to manually write Parcelable code
@Parcelize
class Person(val name: String, val age: Int) : Parcelable
@Parcelize
enum class BookType: Parcelable { HISTORY, DRAMA, FICTION, BIO }
@Parcelize
class Book(val author: Person, val type: BookType) : Parcelable
sealed class Result : Parcelable {
@Parcelize
object Failure : Result
@Parcelize
object Error : Result
@Parcelize
class Success : Result
}
apply plugin: 'kotlin-android-extensions'
Be pragmatic about resources
<!-- styles.xml >
<resources>
...
<style name="Widget.MyApp" parent="android:Widget" />
</resources>
<!-- styles-text.xml >
<resources>
...
<!-- Base text appearance styles -->
<style name="TextAppearance.MyApp" parent="TextAppearance.AppCompat" />
<style name="TextAppearance.MyApp.Regular">
<item name="android:fontFamily">@font/my_font_regular</item>
</style>
</resources>
<!-- colors.xml -->
<resources>
...
<!-- DON'T do this -->
<color name="button_foreground">#FFFFFF</color>
<color name="button_background">#2A91BD</color>
</resources>
<!-- colors.xml -->
<resources>
...
<!-- color pallete -->
<color name="white">#FFFFFF</color>
<color name="brand_blue">#3B92BC</color>
</resources>
<!-- colors.xml -->
<resources>
...
<!-- color pallete -->
<color name="white">#FFFFFF</color>
<color name="brand_blue">#3B92BC</color>
<!-- specialised colors -->
<color name="button_foreground">@color/white</color>
<color name="button_background">@color/brand_blue</color>
</resources>
<!-- styles.xml -->
<resources>
<style name="Widget.MyApp.ConfirmButton">
<item name="android:foreground">@color/button_foreground</item>
<item name="android:background">@color/button_background</item>
</style>
</resources>
<!-- dimens.xml -->
<resources>
...
<!-- font sizes -->
<dimen name="font_small">12sp</dimen>
<dimen name="font_normal">15sp</dimen
<dimen name="font_large">18sp</dimen>
<!-- typical spacing between two views -->
<dimen name="spacing_tiny">4dp</dimen>
<dimen name="spacing_small">10dp</dimen>
<dimen name="spacing_normal">14dp</dimen>
<dimen name="spacing_large">24dp</dimen>
<!-- typical sizes of views -->
<dimen name="button_height_short">32dp</dimen>
<dimen name="button_height_normal">40dp</dimen>
<dimen name="button_height_tall">60dp</dimen>
</resources>
Styles are a collection of view attributes
Themes are a collection of named resources, useful broadly across an app
<!-- themes.xml -->
<style name="Theme.MyApp" parent="…">
<item name="colorPrimary">@color/teal_500</item>
<item name="colorSecondary">@color/pink_200</item>
<item name="android:windowBackground">@color/white</item>
</style>
<!-- themes.xml -->
<style name="Theme.MyApp" parent="…">
<item name="colorPrimary">@color/teal_500</item>
<item name="colorSecondary">@color/pink_200</item>
<item name="android:windowBackground">@color/white</item>
</style>
<!-- my_layout.xml -->
<FrameLayout …
android:background="?attr/colorSurface">
<TextView …
android:textAppearance="?attr/textAppearanceHeadline5"
Memory Leak detection
HTTP & Throwables inspector
Casting of connected devices
Native rendering for After Effects animations
Graphical Assets generators