Save 37% off PRO during our Black Friday Sale! »

LINE Androidアプリの基盤を支える OSSライブラリLich / Kotlin Lich

LINE Androidアプリの基盤を支える OSSライブラリLich / Kotlin Lich

LINE Androidアプリの基盤を支える OSSライブラリLich

セッションの動画はこちら
https://youtu.be/5PNIVPi_0-A

53850955f15249a1a9dc49df6113e400?s=128

LINE Developers
PRO

February 18, 2021
Tweet

Transcript

  1. -*/&גࣜձࣾ-*/&ίϛϡχέʔγϣϯϓϥοτϑΥʔϜ։ൃࣨେੴক๜ -*/&"OESPJEΞϓϦͷج൫Λࢧ͑Δ 044ϥΠϒϥϦ-JDI

  2. "CPVUNF w -*/&ίϛϡχέʔγϣϯϓϥοτϑΥʔϜ։ൃࣨॴଐ w -*/&ΞϓϦͷج൫෦෼ͷ։ൃΛ୲౰ w -*/&%&7%":ʹ΋ొஃ w ݸਓϒϩάͰ͸࠷ۙ"QQMF.ͷ࿩͕όζͬͨ

  3. -*/&ΞϓϦͷ՝୊ w ೥͍ۙྺ࢙͕͋Γɺ͍ΘΏΔʮٕज़తෛ࠴ʯ͕ଟ͍ w ίʔυͷෳࡶ౓͕ߴ͘ɺमਖ਼΍৽ػೳ௥Ճʹ͔͔Δίετ͕େ͖͍ w Ϗϧυʹ͕͔͔࣌ؒΔ w 41%:ϓϩτίϧͷ࠾༻ͳͲͷಠࣗͷ࡞ΓࠐΈ͕ɺ࠷ۙͷ։ൃ؀ڥͷมԽ "OESPJE04΍J04ͷΞοϓσʔτɺ։ൃݴޠ΍ϥΠϒϥϦͷมԽͳͲ

    ʹ ରԠͰ͖͍ͯͳ͍
  4. -*/5ϓϩδΣΫτͷ্ཱͪ͛ w -*/5 -*/&*NQSPWFNFOUGPS/FYU5FOZFBST  w -*/&ΞϓϦͷج൫Λվળ͢ΔͨΊɺΫϥΠΞϯτଆɾαʔόʔଆ૒ํ͕ ڠྗͯ͠ࠓޙ೥Λݟਾ͑ͨվળΛߦ͏ w ओͱͯ͠ωοτϫʔΫϓϩτίϧ΍σʔλಉظ·ΘΓͷվળ

    w ৄࡉ͸-*/&%&7%":ͷηογϣϯʹͯ w IUUQTMJOFEFWEBZMJOFDPSQDPNKQTFTTJPOT"
  5. -*/5ϓϩδΣΫτͷ੒Ռͷ044Խ w -*/5ϓϩδΣΫτͷ੒Ռ͸-*/&ΞϓϦҎ֎ʹ΋ల։͍͖͍ͯͨ͠ w -JCSBSZNPEVMFͱͯ͠ଞͷΞϓϦ΍4%,͔Β΋࢖༻͠΍͘͢͢Δ w ൚༻తͳػೳ͸044ͱͯࣾ͠֎ʹ΋ެ։͢Δ w ֎෦͔ΒͷϑΟʔυόοΫ͕ड͚ΒΕΕ͹࣭ΛΑΓߴΊΒΕΔ w

    -JDIIUUQTHJUIVCDPNMJOFMJDI
  6. -JDI w "OESPJEΞϓϦ޲͚ͷMJCSBSZDPMMFDUJPO w ݱ࣌఺Ͱ͸lDPNQPOFOUz lWJFXNPEFMz lMJGFDZDMFz lPLIUUQz lUISJGUzͷ ͭͷϥΠϒϥϦ͕͋Δ

    w ͦΕͧΕͷϥΠϒϥϦ͸ಠཱ͍ͯ͠ΔͷͰඞཁͳ΋ͷ͚ͩར༻Մೳ w ຊ೔͸l-JDIDPNQPOFOUzʹ͍ͭͯ঺հ IUUQTHJUIVCDPNMJOFMJDI
  7. -JDI$PNQPOFOU w 4JOHMFUPOΦϒδΣΫτͷ؅ཧΛ͢ΔͨΊͷϥΠϒϥϦ w %BHHFS ,PJOͱ͍ͬͨ%*πʔϧͷ୅ΘΓͱͳΔ΋ͷ w طଘͷ%*πʔϧΛஔ͖׵͑ͣʹิ׬తʹར༻͢Δ͜ͱ΋ग़དྷΔ

  8. -JDI$PNQPOFOUͷಛ௃ w ࢖༻͢ΔͨΊʹ֮͑Δ͜ͱ͕গͳ͍ w (MPCBMͳঢ়ଶΛ࣋ͨͣɺ"QQMJDBUJPOPO$SFBUF ͳͲͰͷॳظԽ͕ෆཁ w MB[Z͕,PUMJOͷEFMFHBUFEQSPQFSUZͱͯ͠ॻ͚Δ w JOUFSGBDFͱ࣮૷Λ؆୯ʹ෼཭Ͱ͖Δ

    w -JCSBSZNPEVMF΍%ZOBNJDGFBUVSFNPEVMFͰ΋໰୊ͳ͘ಈ͘ w #VJMEUZQF΍qBWPSʹΑΔ࣮૷ͷ੾Γସ͕͑؆୯ʹͰ͖Δ w 6OJUUFTUͰϞοΫΦϒδΣΫτʹࠩ͠ସ͑Δͷ΋؆୯ w ίʔυੜ੒Λ͠ͳ͍ͷͰϏϧυ͕࣌ؒԆͼͳ͍
  9. جຊతͳ࢖͍ํ  w $PNQPOFOUΛఆٛ͢Δ class FooComponent { // snip... companion

    object : ComponentFactory<FooComponent>() { override fun createComponent(context: Context): FooComponent = FooComponent() } }
  10. جຊతͳ࢖͍ํ  w 'PP$PNQPOFOUͷΠϯελϯεΛऔಘ w 'PP$PNQPOFOUͷΠϯελϯεΛMB[Zʹऔಘ w 'SBHNFOUͰͷ࢖༻ྫ val fooComponent

    = context.getComponent(FooComponent) val fooComponent by context.component(FooComponent) class FooFragment : Fragment() { private val fooComponent by component(FooComponent) // snip... }
  11. JOUFSGBDFͱ࣮૷ͷ෼཭ w ࢖͏ଆ͔Β͸'PP$PNQPOFOUΠϯλʔϑΣʔε͚͕ͩݟ͑Ε͹Α͍ w 'PP$PNQPOFOU*NQM͸೚ҙͷϞδϡʔϧʹஔ͚Δ interface FooComponent { // snip...

    companion object : ComponentFactory<FooComponent>() { override fun createComponent(context: Context): FooComponent = delegateToServiceLoader(context) } } @AutoService(FooComponent::class) class FooComponentImpl : FooComponent { // snip... }
  12. ෳ਺ͷ࣮૷ΫϥεΛ੾Γସ͑Δ EFCVHϏϧυͰ͸%FCVH'PP$PNQPOFOU*NQM ͦΕҎ֎Ͱ͸'PP$PNQPOFOU*NQM͕༻͍ΒΕΔ // path: src/debug/java/DebugFooComponentImpl.kt @AutoService(FooComponent::class) class DebugFooComponentImpl :

    FooComponent, ServiceLoaderComponent { override val loadPriority: Int get() = 10 // snip... } // path: src/main/java/FooComponentImpl.kt @AutoService(FooComponent::class) class FooComponentImpl : FooComponent, ServiceLoaderComponent { override val loadPriority: Int get() = 0 // snip... }
  13. ࣮ߦ࣌ͷίετʹ͍ͭͯ w JOUFSGBDFͱ࣮૷Λ෼཭͢Δػೳ͸+BWBͷ4FSWJDF-PBEFSʹΑ࣮ͬͯݱ w 4FSWJDF-PBEFS͸಺෦ͰϦϑϨΫγϣϯΛ࢖༻ w ϦϦʔεϏϧυͰ͸ɺ3ͷ࠷దԽʹΑΓ4FSWJDF-PBEFSͷݺͼग़͕͠ ΠϯϥΠϯԽ͞ΕΔ w ϦϑϨΫγϣϯͷίʔυ͕আڈ͞ΕɺΦʔόʔϔουθϩʂ

    w ͜ͷ࢓૊Έ͸%ZOBNJDGFBUVSFNPEVMFͰ΋໰୊ͳ͘ಈ࡞͢Δ
  14. 6OJUUFTUͷॻ͖ํ  'PP6TF$BTFͷGPP3FQPTJUPSZΛϞοΫͯ͠ςετ͢Δʹ͸࣍ͷΑ͏ʹॻ͘ class FooRepository(context: Context) { suspend fun findFoo(key:

    String): Foo { /* TODO */ } companion object : ComponentFactory<FooRepository>() { override fun createComponent(context: Context): FooRepository = FooRepository(context) } } class FooUseCase(context: Context) { private val fooRepository by context.component(FooRepository) // snip… }
  15. 6OJUUFTUͷॻ͖ํ  @RunWith(AndroidJUnit4::class) class FooUseCaseTest { @Test fun testFooUseCase() {

    val expectedValue = Foo() // Set a mock of FooRepository. mockComponent(FooRepository) { onBlocking { findFoo(any()) } doReturn expectedValue } val context = ApplicationProvider.getApplicationContext() val fooUseCase = FooUseCase(context) // TODO: Write test cases for fooUseCase. } }
  16. -JDI$PNQPOFOUΛಋೖͨ͠ޮՌ w MB[Z͕؆୯ʹॻ͚ΔͷͰɺىಈ࣌ͷίετΛ࡟ݮ͠΍͘͢ͳͬͨ w ϚϧνϞδϡʔϧؒͷґଘؔ܎ղܾ͕ͱͯ΋؆୯ʹͰ͖ΔΑ͏ʹͳͬͨ w ڊେͳϞϊϦγοΫϓϩδΣΫτͩͬͨ-*/&ΞϓϦ͕ػೳ͝ͱʹ෼ׂ͞Ε ։ൃޮ཰͕Ξοϓͨ͠ w %ZOBNJDGFBUVSFNPEVMFʹΑΓΞϓϦͷ༰ྔΛ࡟ݮͰ͖ΔΑ͏ʹͳͬͨ

  17. '"2 w 4JOHMFUPOҎ֎ͷΦϒδΣΫτ͸ѻ͑ͳ͍ͷ  w 7JFX.PEFMͰ͋Ε͹-JDI7JFX.PEFM͕࢖͑Δ w -JDI$PNQPOFOUͱಉ༷ʹ࢖͑Δ΄͔ɺ4BWFE4UBUFΛEFMFHBUFE QSPQFSUJFTͱͯ͠ૢ࡞͢Δ͜ͱ΋Ͱ͖Δ w

    "DUJWJUZTDPQFE΍'SBHNFOUTDPQFEͳΦϒδΣΫτ͸Ϟμϯͳ "OESPJEΞϓϦͰ͸ෆཁͳ͸ͣ w ϏδωεϩδοΫ͸7JFX.PEFMҎԼͷ૚ʹ࣮૷͠ɺ"DUJWJUZ΍ 'SBHNFOU͸7JFX.PEFMͱ7JFXͷCJOEJOH͚ͩΛߦ͏΂͖
  18. ଞͷ%*πʔϧͱͷ࿈ܞ w ͱ͸͍͑ɺଞͷ%*πʔϧʹ׳Εͨਓʹ͸෺଍Γͳ͍఺΋͋ΔͩΖ͏ w -JDI$PNQPOFOUΛଞͷ%*πʔϧͱ૊Έ߹Θͤͯ࢖͏ͷ΋ྑ͍ w Ϟδϡʔϧؒͷґଘؔ܎ղܾ͚ͩʹ-JDI$PNQPOFOUΛ࢖͏ͳͲ w %BHHFSͱ૊Έ߹Θͤͨྫ @Module

    object FooModule { @Provides fun provideFooComponent(application: Application): FooComponent = application.getComponent(FooComponent) }
  19. ·ͱΊ w -JDI͸-*/&ΞϓϦͷվળϓϩδΣΫτͷதͰੜ·Εͨ044ϥΠϒϥϦ w IUUQTHJUIVCDPNMJOFMJDI w -JDI$PNQPOFOU͸ΞϓϦͷϚϧνϞδϡʔϧԽΛࢧԉ͢ΔͨΊʹ࡞ΒΕͨ %*πʔϧ w ܰྔ͔ͭߴ଎Ͱ͋Δ఺΋ΞϐʔϧϙΠϯτ

    w %BHHFSͳͲͷଞͷ%*πʔϧͱ૊Έ߹Θͤͯ࢖͏ͷ΋ྑ͍ w -JDIʹ͸7JFX.PEFM΍0L)UUQͷར༻Λࢧԉ͢ΔͨΊͷϥΠϒϥϦ΋͋Δ
  20. 5IBOLZPV