Share
Embed
Becoming an Android Librarian (Android World Wide 2023 Jan)
Becoming an Android Librarian (Android World Wide 2023 Jan)
Jaewoong
February 01, 2023
Transcript
91 slides
-
G E T S T R E A M .
I O Becoming an Android Librarian -
G E T S T R E A M .
I O skydoves @github_skydoves Android Developer Advocate @ Stream Jaewoong Eum -
G E T S T R E A M .
I O Open-Source Libraries -
G E T S T R E A M .
I O Open-Source Libraries -
G E T S T R E A M .
I O Library & SDK Lifecycles Design Develop Prepare Release -
G E T S T R E A M .
I O Library & SDK Lifecycles Design Develop Prepare Release Design process -
G E T S T R E A M .
I O Library & SDK Lifecycles Design process 1. Define a problem 2. Research overall ideas 3. Verify the feasibility of your ideas 4. Investigate dependencies 5. Draw blueprints of application interfaces 6. Design the application interfaces -
G E T S T R E A M .
I O Library & SDK Lifecycles Design Develop Prepare Release Development strategies -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces Module Public Interface -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces Client Client Client Client -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces Client Client Client Client -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces Client Client Client Client -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces Public Internal -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces Client Client Client Client Public Internal -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces Client Client Client Client -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces Client Client Client Client -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces private internal importance protected public -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces private internal importance protected public Client Client Client -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces class ApiResponseCallAdapter constructor( val resultType: Type ) : CallAdapter<Type, Call<ApiResponse<Type>>> { override fun responseType(): Type { return resultType } override fun adapt(call: Call<Type>): Call<ApiResponse<Type>> { return ApiResponseCallDelegate(call) } } Client -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces internal class ApiResponseCallAdapter constructor( private val resultType: Type ) : CallAdapter<Type, Call<ApiResponse<Type>>> { override fun responseType(): Type { return resultType } override fun adapt(call: Call<Type>): Call<ApiResponse<Type>> { return ApiResponseCallDelegate(call) } } Client -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces fun Context.dp2Px(dp: Int): Int { val scale = resources.displayMetrics.density return (dp * scale).toInt() } fun Context.px2Sp(px: Int): Int { val scale = resources.displayMetrics.scaledDensity return (px / scale).toInt() } val px = context.dp2Px(dp = 22) val sp = context.px2Sp(px = 22) -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces internal fun Context.dp2Px(dp: Int): Int { val scale = resources.displayMetrics.density return (dp * scale).toInt() } internal fun Context.px2Sp(px: Int): Int { val scale = resources.displayMetrics.scaledDensity return (px / scale).toInt() } val px = context.dp2Px(dp = 22) // Unresolved reference val sp = context.px2Sp(px = 22) // Unresolved reference -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces internal fun Context.dp2Px(dp: Int): Int { val scale = resources.displayMetrics.density return (dp * scale).toInt() } internal fun Context.px2Sp(px: Int): Int { val scale = resources.displayMetrics.scaledDensity return (px / scale).toInt() } int px = ContextExtensionKt.dp2Px(context, 11); int sp = ContextExtensionKt.px2Sp(context, 11); -
G E T S T R E A M .
I O Development Strategies Minimize API surfaces @JvmSynthetic internal fun Context.dp2Px(dp: Int): Int { val scale = resources.displayMetrics.density return (dp * scale).toInt() } @JvmSynthetic internal fun Context.px2Sp(px: Int): Int { val scale = resources.displayMetrics.scaledDensity return (px / scale).toInt() } int px = ContextExtensionKt.dp2Px(context, 11); // Unresolved reference int sp = ContextExtensionKt.px2Sp(context, 11); // Unresolved reference -
G E T S T R E A M .
I O Development Strategies Explicit API mode -
G E T S T R E A M .
I O Development Strategies Explicit API mode -
G E T S T R E A M .
I O Development Strategies Explicit API mode -
G E T S T R E A M .
I O Development Strategies Explicit API mode -
G E T S T R E A M .
I O Development Strategies Explicit API mode -
G E T S T R E A M .
I O Development Strategies Binary Compatibility Validator -
G E T S T R E A M .
I O Development Strategies Binary Compatibility Validator build.gradle module.gradle On terminal -
G E T S T R E A M .
I O Development Strategies Binary Compatibility Validator module.api -
G E T S T R E A M .
I O Development Strategies Binary Compatibility Validator -
G E T S T R E A M .
I O Development Strategies Metalava -
G E T S T R E A M .
I O Development Strategies Exposing resources /classes.jar /res/ /R.txt /public.txt /assets/ /libs/name.jar /jni/abi_name/name.so /proguard.txt /lint.jar /api.jar AAR file -
G E T S T R E A M .
I O Development Strategies Exposing resources /classes.jar /res/ /R.txt /public.txt /assets/ /libs/name.jar /jni/abi_name/name.so /proguard.txt /lint.jar /api.jar AAR file res/drawable res/layout res/menu res/values res/xml res/raw res/anim res/animator res/mipmap res/font string.xml colors.xml styles.xml dimens.xml arrays.xml … /res/ /res/values/ -
G E T S T R E A M .
I O Development Strategies Exposing resources <resources> <color name="white">#FFFFFF</color> <color name="black">#000000</color> <color name="blue">#57A8D8</color> <color name="yellow">#FBC02D</color> </resources> Library (colors.xml) Project val whiteColor = ContextCompat.getColor(this, R.color.white) binding.myView.setBackgroundColor(whiteColor) <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="skydoves" android:textColor="@color/yellow" /> -
G E T S T R E A M .
I O Development Strategies Exposing resources <resources> <color name="white">#FFFFFF</color> <color name="black">#000000</color> <color name="blue">#57A8D8</color> <color name="yellow">#FBC02D</color> </resources> Library (colors.xml) val whiteColor = ContextCompat.getColor(this, R.color.white) binding.myView.setBackgroundColor(whiteColor) <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="skydoves" android:textColor="@color/yellow" /> Project compile error! -
G E T S T R E A M .
I O Development Strategies Exposing resources <public /> -
G E T S T R E A M .
I O Development Strategies Exposing resources <?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools"> <!-- Definitions of layouts to be exposed as public ⟶ <public name="balloon_layout_body" type="layout" /> <public name="balloon_layout_overlay" type="layout" /> <!-- Definitions of attributes to be exposed as public ⟶ <public name="balloon_drawableStart" type="attr" /> <public name="balloon_drawableEnd" type="attr" /> <public name="balloon_drawableTop" type="attr" /> <public name="balloon_drawableBottom" type="attr" /> <public name="balloon_drawablePadding" type="attr" /> <public name="balloon_drawableTintColor" type="attr" /> <public name="balloon_drawableWidth" type="attr" /> <public name="balloon_drawableHeight" type="attr" /> <public name="balloon_drawableSquareSize" type="attr" /> Library (/res/values/public.xml) -
G E T S T R E A M .
I O Development Strategies Exposing resources <?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools"> <!-- Definitions of layouts to be exposed as public ⟶ <public name="balloon_layout_body" type="layout" /> <public name="balloon_layout_overlay" type="layout" /> <!-- Definitions of attributes to be exposed as public ⟶ <public name="balloon_drawableStart" type="attr" /> <public name="balloon_drawableEnd" type="attr" /> <public name="balloon_drawableTop" type="attr" /> <public name="balloon_drawableBottom" type="attr" /> <public name="balloon_drawablePadding" type="attr" /> <public name="balloon_drawableTintColor" type="attr" /> <public name="balloon_drawableWidth" type="attr" /> <public name="balloon_drawableHeight" type="attr" /> <public name="balloon_drawableSquareSize" type="attr" /> Library (/res/values/public.xml) res/drawable res/layout res/menu res/values res/xml res/raw res/anim res/animator res/mipmap res/font String.xml attrs.xml colors.xml styles.xml dimens.xml arrays.xml /res/ /res/values/ -
G E T S T R E A M .
I O Development Strategies Exposing resources Project (XML) Project (code) -
G E T S T R E A M .
I O Development Strategies Exposing resources Project (XML) Project (code) -
G E T S T R E A M .
I O Development Strategies Exposing resources -
G E T S T R E A M .
I O Development Strategies Exposing resources -
G E T S T R E A M .
I O Development Strategies Exposing resources Library (layout_balloon.xml) Library (Balloon.Builder.kt) -
G E T S T R E A M .
I O Development Strategies Exposing resources • Some issues have been reported in Crashlytics. • But the reports were not helpful at all. • Occasionally the library behaves very weirdly. • Also it’s really difficult to reproduce. -
G E T S T R E A M .
I O Development Strategies Exposing resources Perhaps..? -
G E T S T R E A M .
I O Development Strategies Exposing resources <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:clipChildren="false" android:clipToPadding="false" android:padding="10dp"> <com.skydoves.balloon.vectortext.VectorTextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:textColor="@android:color/white" /> … Library (layout_balloon.xml) Project (layout_balloon.xml) <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:clipChildren="false" android:clipToPadding="false" android:padding="10dp"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:text="skydoves" android:textSize="16sp" android:textStyle="bold" /> ... -
G E T S T R E A M .
I O Development Strategies Exposing resources <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:clipChildren="false" android:clipToPadding="false" android:padding="10dp"> <com.skydoves.balloon.vectortext.VectorTextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:textColor="@android:color/white" /> … Library (layout_balloon.xml) // wrong behaviors Project (layout_balloon.xml) // runtime error! <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:clipChildren="false" android:clipToPadding="false" android:padding="10dp"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:text="skydoves" android:textSize="16sp" android:textStyle="bold" /> ... -
G E T S T R E A M .
I O Development Strategies Resource prefix resourcePrefix -
G E T S T R E A M .
I O Development Strategies Resource prefix resourcePrefix -
G E T S T R E A M .
I O Development Strategies Resource prefix build.gradle -
G E T S T R E A M .
I O Development Strategies Resource prefix layout_balloon.xml attrs.xml -
G E T S T R E A M .
I O Development Strategies Resource prefix -
G E T S T R E A M .
I O Development Strategies R class Non transitive R class -
G E T S T R E A M .
I O Development Strategies Non transitive R class -
G E T S T R E A M .
I O Development Strategies Non transitive R class -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :library :material (MDC) implementation implementation -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :library :material (MDC) com.google.android.material.R (:material) implementation implementation -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :library :material (MDC) com.my.library.R (:material) (:library) com.google.android.material.R (:material) implementation implementation -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :library :material (MDC) com.my.library.R (:material) (:library) com.google.android.material.R (:material) com.my.app.R (:material) (:library) (:app) implementation implementation -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :library :material (MDC) Transitive dependency com.my.library.R (:material) (:library) com.google.android.material.R (:material) com.my.app.R (:material) (:library) (:app) implementation implementation -
G E T S T R E A M .
I O Development Strategies Non transitive R class com.my.library.R (:material) (:library) -
G E T S T R E A M .
I O Development Strategies Non transitive R class -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :library :material (MDC) implementation implementation com.my.library.R (:material) (:library) com.google.android.material.R (:material) com.my.app.R (:material) (:library) (:app) Wow, a million of LoC in R classes in a minute! -
G E T S T R E A M .
I O Development Strategies Non transitive R class Dex format has 64K limit for methods and fields references! 64K (65,536 = 64 x 1024 (2^10)) -
G E T S T R E A M .
I O Development Strategies Non transitive R class -
G E T S T R E A M .
I O Development Strategies Non transitive R class android.nonTransitiveRClass=true gradle.properties -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :library implementation implementation com.my.library.R (:library) com.google.android.material.R (:material) com.my.app.R (:app) Refer to its own resources without pulling resources from dependencies. nonTransitiveRclass :material (MDC) -
G E T S T R E A M .
I O Development Strategies Non transitive R class Before After (enabled non transitive R class) -
G E T S T R E A M .
I O Development Strategies Non transitive R class aar size diff 226054 bytes -> 214538 bytes (11516 bytes reduced) 10,000 end-users 2260540000 bytes -> 2145380000 bytes (≈115 MB reduced) 100,000 end-users 22605400000 bytes -> 21453800000 bytes (≈1.1 GB reduced) 1,000,000 end-users 226054000000 bytes -> 214538000000 bytes (≈10 GB reduced) 100,000,000 end-users 22605400000000 bytes -> 21453800000000 bytes (≈1 TB reduced) -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :feature1 :feature2 :feature3 com.my.app.R (:feature1) (:feature2) (:feature3) (:app) Unresolved reference -
G E T S T R E A M .
I O Development Strategies Non transitive R class :app :feature1 :feature2 :feature3 com.my.app.R (:feature1) (:feature2) (:feature3) (:app) full name package import with namespacing -
G E T S T R E A M .
I O Library & SDK Lifecycles Design Develop Prepare Release -
G E T S T R E A M .
I O Preparation Documentation (KDoc) -
G E T S T R E A M .
I O Preparation Documentation (Dokka) ./gradlew dokkaHtml ./gradlew dokkaHtmlMultiModule ./gradlew dokkaJavadoc -
G E T S T R E A M .
I O Preparation Documentation (README) -
G E T S T R E A M .
I O Library & SDK Lifecycles Design Develop Prepare Release -
G E T S T R E A M .
I O Release Maven -
G E T S T R E A M .
I O Release Maven repositories mavenCentral() google() jcenter() -
G E T S T R E A M .
I O Release Maven central repository 1. Registering a Sonatype account 2. Generating a GPG key pair 3. Setting up publication in your project a. Maven publishing setup with Gradle b. Signing artifacts with GPG key c. Configure pom files d. Per-module Gradle setup 4. Publish to sonatype repository 5. Evaluate and close the ticket on staging repositories -
G E T S T R E A M .
I O Release Maven central repository 🔗 https://bit.ly/386yJt1 -
G E T S T R E A M .
I O Release Jitpack maven { url 'https://jitpack.io' } -
G E T S T R E A M .
I O Library & SDK Lifecycles Design Develop Prepare Release Verification -
G E T S T R E A M .
I O Verifying and Marketing Community -
G E T S T R E A M .
I O Verifying and Marketing Technical contents -
G E T S T R E A M .
I O Verifying and Marketing Example projects Codes speak louder than words! -
G E T S T R E A M .
I O Blog Post 🔗 https://bit.ly/3Qim5ZB -
G E T S T R E A M .
I O https://github.com/skydoves [email protected] https://twitter.com/github_skydoves https://medium.com/@skydoves Contact -
G E T S T R E A M .
I O Thank you.