新 Kyash Card を支える技術

新 Kyash Card を支える技術

Bonfire Android #6 での発表資料です
https://yj-meetup.connpass.com/event/158328/

Fcd25eb13edba05537f72ede148107d7?s=128

Yoshihiro Tanaka

January 16, 2020
Tweet

Transcript

  1. None
  2. Bonfire Android #6 ৽ Kyash Card Λࢧ͑Δٕज़

  3. 3 • 2019/05 ~ Kyash Inc. • Android applications engineer

    • Kyash Point • Kyash Card • ࣮ݧతػೳ • ͳͲ Yoshihiro Tanaka (@_Cordea)
  4. 4 Kyash Card

  5. 5 2020೥ॳΊࠒൃߦ༧ఆ

  6. 6 • Kyash Card ͷਃ͠ࠐΈ΍ΧʔυઃఆͳͲ • ৽نͷը໘਺͸ 30 ~ 40

    • Kyash ͷதͰ͸ൺֱతେ͖Ίͷ։ൃن໛ͳͷͰɺઃܭ΍࠾༻ٕज़΋ݟ௚͠ • ࠓճ͸͜ͷ΁Μͷ࿩Λ͠·͢ ΞϓϦ΋͍Ζ͍Ζ௥Ճ͞Ε·͢
  7. 7 • Architecture ͸ MVVM • Databinding Ͱ VM ͱ

    View Λ bind • BaseViewModel ͸ࣗ෼ͨͪͰ࡞ͬͨ΋ͷ • ࠾༻ٕज़ • Dagger 2, Retrofit, RxJava ͳͲඪ४తͳબ୒ • Kyash Point ͷࡍʹ androidx.paging Λ࠾༻͢ΔͳͲ͍ͯ͠Δ ͜Ε·Ͱͷ Kyash Android
  8. 8 Kyash Card ։ൃʹ͋ͨͬͯߟ͑ͨ͜ͱ

  9. 9 • Kyash Android ͷ։ൃ͸ࠓ 1.2 ਓ͘Β͍ • ࣌ؒͱϦιʔε͕গͳ͍ •

    ৽ػೳ΋վળ΋΍Γ͍ͨ͜ͱ͸େྔʹ͋Δ • ৽͘͠ਓ͕ೖ͖ͬͯͨ࣌ʹ΋ֶशίετ͸௿͘཈͍͑ͨ
  10. 10 ඪ४ʹد͍ͤͨʂ

  11. 11 • ConstraintLayout • androidx.lifecycle.ViewModel • Navigation component <- New!

    • SpringAnimation <- New! • Kakao <- New! ࢖༻ٕͨ͠ज़
  12. 12 • ͓ೃછΈͷ΍ͭ • ৽نͷը໘͸΄΅ ConstraintLayout ʹͳ͍ͬͯΔ • Kyash ͳΒͰ͸ͷԿ͔ͱ͍͏͜ͱͰʮΧʔυ݊໘ͷඳըʯΛ঺հ

    ConstraintLayout
  13. 13 Kyash Card Lite • PAN ͸ Custom view •

    Autosizing Ͱ Text size Λௐ੔ • جຊͷϥΠϯΛ Guideline Ͱఆٛ͠ɺ֤ཁૉͰ percent, chainStyle, bias ͳͲΛઃఆͯ͠૬ޓʹ ઀ଓ͠ܗΛอ͍ͬͯΔ • ཁ͢ΔʹՄಡੑ͕௿͍
  14. 14 Kyash Card Lite • PAN ͸ Custom view •

    Autosizing Ͱ Text size Λௐ੔ • جຊͷϥΠϯΛ Guideline Ͱఆٛ͠ɺ֤ཁૉͰ percent, chainStyle, bias ͳͲΛઃఆͯ͠૬ޓʹ ઀ଓ͠ܗΛอ͍ͬͯΔ • ཁ͢ΔʹՄಡੑ͕௿͍
  15. 15 Kyash Card Lite <TextView android:id="@+id/exp_label" app:autoSizeMinTextSize="5sp" app:autoSizeTextType="uniform" app:layout_constraintBottom_toTopOf="@id/exp" app:layout_constraintEnd_toEndOf="@id/exp"

    app:layout_constraintHeight_percent="0.05" app:layout_constraintStart_toStartOf="@id/exp" app:layout_constraintTop_toBottomOf="@id/guideline" /> <TextView android:id="@+id/exp" android:layout_marginStart="16dp" app:autoSizeMinTextSize="12sp" app:autoSizeTextType="uniform" app:layout_constraintEnd_toStartOf="@id/cvv" app:layout_constraintHeight_percent="0.08" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/exp_label" app:layout_constraintWidth_percent="0.2" />
  16. 16 Kyash Card • ͢΂ͯ TextView • Autosizing Ͱ Text

    size Λௐ੔ • ֤ཁૉͷҐஔؔ܎Λ Guideline Ͱఆٛ͠ɺը૾ʹ ର͢Δ percent Ͱࢦఆ͢Δ • ͞Βʹ weight ͰͦΕͧΕͷ size Λௐ੔͢Δ
  17. 17 Kyash Card • ͢΂ͯ TextView • Autosizing Ͱ Text

    size Λௐ੔ • ֤ཁૉͷҐஔؔ܎Λ Guideline Ͱఆٛ͠ɺը૾ʹ ର͢Δ percent Ͱࢦఆ͢Δ • ͞Βʹ weight ͰͦΕͧΕͷ size Λௐ੔͢Δ
  18. 18 Kyash Card <TextView android:id="@+id/exp" app:autoSizeMinTextSize="5sp" app:autoSizeTextType="uniform" app:layout_constraintBottom_toTopOf="@id/bottom_guideline" app:layout_constraintEnd_toStartOf="@id/end_guideline" app:layout_constraintHorizontal_weight="2"

    app:layout_constraintStart_toEndOf="@id/good_thru" app:layout_constraintTop_toBottomOf="@id/month_year" app:layout_constraintVertical_weight="2" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/top_guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_percent="0.1" />
  19. 19 • Space ΍ ratio ΋ۦ࢖͢Ε͹ෳࡶͳ Layout ΋ ConstraintLayout Ͱ׬݁Ͱ͖Δ

    • Preview ͰҰݟͯ͠෼͔Βͳ͍ෳࡶ͞͸อकͰ͖ͳ͍ ConstraintLayout
  20. 20 • Kyash Card ͷ৽نը໘Ͱ͸͢΂ͯ androidx.lifecycle.ViewModel ʹ౷Ұ • Navigation component

    ͸΋ͱ΋ͱ࠾༻͍ͨ͠ͱ͍͏࿩͕͋ͬͨͷͰ࠾༻ • ෳ਺ͷը໘ؒͰڞ༗͞ΕΔ Data ΍ Event Ͱ͸ Shared ViewModel Λ࢖༻ • ਃ͠ࠐΈͷঢ়ଶ؅ཧͷͨΊ • Nav graph ͕ෳ਺ʹͳ͍ͬͯΔͷͰͦΕຖʹ Shared ViewModel Λ഑ஔ ViewModel & Navigation component
  21. 21 • ී௨ʹ࢖༻͢ΔͱඞཁҎ্ͷ Data ʹΞΫηεͰ͖ͯ͠·͏ • A Fragment ༻ͷ Data

    ʹ B Fragment ͕ΞΫηεͰ͖ͯ͠·͏ • ҆શͰ͸ͳ͍ • ςετͮ͠Β͍ Shared ViewModel • A Fragment, B Fragment ༻ʹ Interface Λ੾Γɺ͜ΕΛ Inject ͢Δ
  22. 22 Shared ViewModel ͷ Inject interface CardApplicationSharedViewModel { fun apply()

    } interface AddressRegistrationSharedViewModel { fun register() } class CardApplicationSharedViewModelImpl( ) : ViewModel(), CardApplicationSharedViewModel, AddressRegistrationSharedViewModel { override fun apply() { } override fun register() { } } @Module class CardApplicationSharedViewModelProvideModule { @Provides fun provideSharedViewModel(activity: AppCompatActivity): CardApplicationSharedViewModel = ViewModelProviders.of(activity).get<CardApplicationSharedViewModelImpl>() } class CardApplicationFragment : Fragment() { @Inject lateinit var sharedViewModel: CardApplicationSharedViewModel }
  23. 23 • ϩδοΫΛ Shared ViewModel ʹؚΊΔͱҰؾʹෳࡶԽ͢Δ • ੹຿Λ͔ͳΓ੍ݶͯ͠ӡ༻͢Δඞཁ͕͋Δ • ·ͣ͸࢖Θͳͯ͘ྑ͍Α͏ͳํ๏Λߟ͑Δͷ͕͓͢͢Ί

    Shared ViewModel
  24. 24 • View ʹόωͷΑ͏ͳಈ͖Λ༩͑Δɻݮਰൺ΍߶ੑͳͲΛઃఆͰ͖Δɻ • Kyash Card ͷਃ͠ࠐΈͳͲɺཁॴཁॴʹ༷ʑͳ Animation ͕࢓ࠐ·Ε͍ͯ·͢

    • ΆΑΜΆΑΜ͕͍͔ͭ͋͘Γ͜ΕΛ͍͍ײ͡ʹදݱ͍ͨ͠ͷͰ࠾༻ SpringAnimation
  25. 25 SpringAnimation fun startAnimation() { scaleX = 1.5f SpringAnimation(this, SpringAnimation.SCALE_X,

    1f) .apply { spring.dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY spring.stiffness = SpringForce.STIFFNESS_LOW } .start() }
  26. 26 SpringAnimation

  27. 27 • ؆୯ʹɺΑΓࣗવͳಈ͖Λ࣮૷Ͱ͖Δ • BounceInterpolator ͳͲͷ Interpolator ͱͲͪΒ͕ྑ͍͔ߟ͑ͳ͕Β࢖͏ͷ͕ྑ͍ SpringAnimation

  28. 28 • Espresso ͷ DSL • UI tests Λॻ͖΍ͯ͘͘͢͠ΕΔ •

    ςετΛॻ͘͜ͱࣗମʹ࣌ؒΛ͔͚Δͷ͸ຊ࣭తͰ͸ͳ͍ • ਃ͠ࠐΈͳͲͷҰ࿈ͷྲྀΕΛਓͷखΛ࢖Θͣʹ࣮ߦ͢Δ Kakao
  29. 29 Espresso object InputPageObject { fun setFirstName() = apply {

    onView(withId(R.id.first_name_edit_text)).perform(replaceText("Taro")) } fun setLastName() = apply { onView(withId(R.id.last_name_edit_text)).perform(replaceText("Kyash")) } fun clickButton() = apply { onView(withText(getString(R.string.button))).perform(click()) } } class InputTest { @Test fun test() { InputPageObject .setFirstName() .setLastName() .clickButton() } }
  30. 30 Kakao class InputScreen : Screen<InputScreen>() { val firstNameEditText =

    KEditText { withId(R.id.first_name_edit_text) } val lastNameEditText = KEditText { withId(R.id.last_name_edit_text) } val button = KButton { withText(getString(R.string.button)) } } class InputTest { @Test fun test() { onScreen<InputScreen> { firstNameEditText { replaceText("Taro") } lastNameEditText { replaceText("Kyash") } button.click() } } }
  31. 31 Kakao class ExampleScreen : Screen<ExampleScreen>() { val recyclerView =

    KRecyclerView({ withId(R.id.recycler_view) }) { itemType(::Item) } class Item(parent: Matcher<View>) : KRecyclerItem<Item>(parent) { val title = KTextView(parent) { withId(R.id.title) } val description = KTextView(parent) { withId(R.id.description) } } } class ExampleTest { @Test fun test() { onScreen<ExampleScreen> { recyclerView.children<ExampleScreen.Item> { title { isVisible() hasAnyText() } description { isVisible() isNotClickable() hasEmptyText() } } } } }
  32. 32 • UI tests Λॻ࣌ؒ͘͸୹͘ͳΔ • Espresso ͔Βॻ͖׵͑ͨՕॴͰͨ·ʹࣦഊ͢Δ͜ͱ͕͋Δ • λΠϛϯά΍

    Delay ͸গ͠ௐ੔͢Δඞཁ͕͋ͬͨΓ͢Δ͔΋ Kakao
  33. 33 • ConstraintLayout ͸ԿͰ΋ग़དྷΔ • ΍Γ͗͢ΔͱՄಡੑΛԼ͛Δ • Shared ViewModel ͷ࢖༻͸৻ॏʹ

    • UI tests ʹྗΛೖΕ͍ͯΔ৔߹͸ Kakao ͕ศར ·ͱΊ
  34. Thank you 34

  35. None