$30 off During Our Annual Pro Sale. View Details »

Android Bazaar and Conference Diverse 2021 Winter

ARIYAMA Keiji
December 11, 2021

Android Bazaar and Conference Diverse 2021 Winter

11/12/2021に開催された Android Bazaar and Conference Diverse 2021 Winter で発表した 「COCOA 1.4.0 障害はなぜ起きたのか」の発表資料です。

https://japan-android-group.connpass.com/event/228215/
https://abc.android-group.jp/abcd2021w/

リンクが有効なPDFは、プレゼンテーション下のボタンからダウンロードできます。
アーカイブPDF: https://blog.keiji.dev/archives/abcd2021-winter.pdf

本資料の内容は、
技術情報の提供を通じた技術的なコミュニケーションを目的としており、
発表者の所属または関与する組織の公式見解、方針等を述べるものではありません。

ARIYAMA Keiji

December 11, 2021
Tweet

More Decks by ARIYAMA Keiji

Other Decks in Technology

Transcript

  1. ARIYAMA Keiji - σδλϧிAndroidʢΞϓϦʣΤϯδχΞ / ༗ݶձࣾγʔϦε୅ද
    COCOA 1.4.0 ো֐͸

    ͳͥى͖ͨͷ͔
    1

    View Slide

  2. ༗ࢁܓೋʢ"3*:".",FJKJʣ
    σδλϧி"OESPJEʢΞϓϦʣΤϯδχΞ

    $-*4$0 -5%୅ද
    Photo : Koji MORIGUCHI (MORIGCHOWDER)
    !LFJKJ@BSJZBNB
    keiji
    "OESPJEΞϓϦ։ൃऀ

    View Slide

  3. ໔੹ࣄ߲
    Disclaimer
    3
    ຊࢿྉͷ಺༰͸ɺ

    ٕज़৘ใͷఏڙΛ௨ٕͨ͡ज़తͳίϛϡχέʔγϣϯΛ໨తͱ͓ͯ͠Γɺ

    ॴଐ·ͨ͸ؔ༩͢Δ૊৫ͷެࣜݟղɺํ਑౳Λड़΂Δ΋ͷͰ͸͋Γ·ͤΜɻ

    View Slide

  4. ઀৮֬ೝΞϓϦ
    COVID-19 Contact-Con
    fi
    rming Application
    https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/cocoa_00138.html
    ʠްੜ࿑ಇল͸ɺ৽ܕίϩφ΢Πϧεײછ঱ͷ֦େ๷ࢭʹ
    ࢿ͢ΔΑ͏ɺ৽ܕίϩφ΢Πϧεײછ঱ରࡦςοΫνʔϜͱ
    ࿈ܞͯ͠ɺ৽ܕίϩφ΢Πϧε઀৮֬ೝΞϓϦʢ$0$0"
    ˞ʣΛ։ൃ͠·ͨ͠ɻࣗ͝਎ͷεϚʔτϑΥϯʹΠϯετʔ
    ϧͯ͠ɺར༻͍͖ͨͩ·͢Α͏͓ئ͍͠·͢ʡ
    ʢްੜ࿑ಇল΢ΣϒαΠτΑΓʣ
    4

    View Slide

  5. 5
    https://play.google.com/store/apps/details?id=jp.go.mhlw.covid19radar&hl=ja
    Android൛
    https://apps.apple.com/jp/app/id1516764458
    iOS൛

    View Slide

  6. COCOA Open Source Project
    • WebαΠτ

    https://cocoa-mhlw.github.io/cocoa/

    • GitHub ϦϙδτϦ

    https://github.com/cocoa-mhlw/cocoa
    6

    View Slide

  7. COCOA։ൃମ੍ ུ֓ਤ
    7
    (JU)VCίϛϡχςΟ ։ൃνʔϜ
    ࿈ܞνʔϜ
    "3*:"."

    View Slide

  8. ໨࣍
    ͳʹ͕ى͖ͨͷ͔

    ো֐͸ɺͳͥى͖ͨͷ͔

    ࠓޙͷରԠ

    ݕ౼தͷ࠶ൃ๷ࢭࡦ
    8

    View Slide

  9. ͳʹ͕ى͖ͨͷ͔
    9

    View Slide

  10. v1.4.0 ϦϦʔε


    2021/11/25 15:00
    10

    View Slide

  11. 11
    https://github.com/cocoa-mhlw/cocoa/issues/517
    2021/11/25 16:17

    View Slide

  12. 12
    16:20

    View Slide

  13. 13
    16:49

    View Slide

  14. 14
    17:11
    Xamarin android App crashes with error android.runtime.JavaProxyThrowable reported in Google Play Console Vitals

    https://docs.microsoft.com/en-us/answers/questions/418448/xamarin-android-app-crashes-with-error-androidrunt.html

    View Slide

  15. ΤϥʔൃੜՕॴ
    15
    https://github.com/cocoa-mhlw/cocoa/blob/release_1_4_0/Covid19Radar/Covid19Radar/Services/Migration/Migrator_1_3_0.cs
    private void MigrateDateTimeToEpoch(string dateTimeKey, string epochKey, TimeSpan differential)


    {


    string dateTimeStr = _preferencesService.GetValue(dateTimeKey, DateTime.UtcNow.ToString());


    DateTime dateTime;


    try


    {


    dateTime = DateTime.SpecifyKind(DateTime.Parse(dateTimeStr) + differential, DateTimeKind.Utc);


    }


    catch (FormatException exception)


    {


    _loggerService.Exception($"Parse dateTime FormatException occurred. {dateTimeStr}", exception);


    dateTime = DateTime.UtcNow;


    }


    _preferencesService.SetValue(epochKey, dateTime.ToUnixEpoch());


    _preferencesService.RemoveValue(dateTimeKey);


    }


    View Slide

  16. 16
    17:30

    View Slide

  17. 17
    18:07

    View Slide

  18. Hotfix
    18
    Hot
    fi
    x #517

    https://github.com/cocoa-mhlw/cocoa/pull/518
    private void MigrateDateTimeToEpoch(string dateTimeKey, string epochKey, TimeSpan differential, DateTime fallbackDateTime)


    {


    string dateTimeStr = _preferencesService.GetValue(dateTimeKey, fallbackDateTime.ToString());


    DateTime dateTime;


    try


    {


    dateTime = DateTime.SpecifyKind(DateTime.Parse(dateTimeStr), DateTimeKind.Utc);


    }


    catch (FormatException exception)


    {


    _loggerService.Exception($"Parse dateTime FormatException occurred. {dateTimeStr}", exception);


    dateTime = fallbackDateTime;


    }


    try


    {


    dateTime += differential;


    }


    catch (ArgumentOutOfRangeException exception)


    {


    _loggerService.Exception($"{dateTimeStr} {differential} The added or subtracted value results in an un-representable DateTime.", exception);


    }


    _preferencesService.SetValue(epochKey, dateTime.ToUnixEpoch());


    _preferencesService.RemoveValue(dateTimeKey);


    }


    18:35

    View Slide

  19. 19
    19:19

    View Slide

  20. 20
    2021/11/26 00:28

    View Slide

  21. 21
    * 20:12 - ։ൃνʔϜ ར༻ऀ͔Βͷ໰͍߹Θͤঢ়گΛڞ༗


    * 20:13 - ։ൃνʔϜ v1.1.5ҎલʹΞϓϦͷར༻Λ։࢝͢Δͱར༻ن໿ͷಉҙ೔෇͕DateTime࠷খ஋ͷ··ͱͳΔ͜ͱ͕ݪҼͱ൑໌


    * ։ൃνʔϜ ো֐ͷ࠶ݱํ๏Λ֬ఆ


    * 20:39 - ։ൃνʔϜ ϦϦʔεςετͷ࡞੒։࢝


    * 22:40 - ։ൃνʔϜ ϦϦʔεςετͷ࡞੒׬ྃ


    * 23:16 - ։ൃνʔϜ ϦϦʔεςετͷ࣮ࢪ׬ྃ


    * ։ൃνʔϜ ४උͨ͠v1.4.0͕Ϋϥογϡ͢Δ୺຤ͷΞϓϦΛ੡඼൛ΞϓϦv1.4.1΁Ξοϓσʔτɺਖ਼ৗىಈ͠໰୊͕ղফ͍ͯ͠Δ͜ͱΛ֬ೝ
    26/11/2021 00:28
    2021/11/25 19:19

    View Slide

  22. v1.4.1 HotfixϦϦʔε
    22
    GitHubίϛϡχςΟͷΈͳ͞Μ
    ͝ڠྗɺຊ౰ʹ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ
    * 11/26


    * 00:28 - ։ൃνʔϜ v1.4.1 ৹ࠪఏग़׬ྃʢGoogle Play, AppStoreʣ


    * 10:10 - ։ൃνʔϜ v1.4.1 AppStoreͰϦϦʔε


    * ։ൃνʔϜ iOS୺຤7୆Ͱެ։͞ΕͨΞϓϦv1.4.1͕ىಈͰ͖Δ͜ͱΛ֬ೝ


    * 10:47 - GitHub iOS൛ͷ෮چใࠂ


    * 11/27


    * 11:28 - ։ൃνʔϜ v1.4.1 Google PlayͰϦϦʔε։࢝


    * 11:40 - GitHub Android൛ͷ෮چใࠂ


    * ։ൃνʔϜ Android୺຤1୆Ͱެ։͞ΕͨΞϓϦv1.4.1͕ىಈͰ͖Δ͜ͱΛ֬ೝ

    View Slide

  23. ো֐͸ɺͳͥى͖ͨͷ͔
    23

    View Slide

  24. ͜ͷॲཧ͸ͳʹʁ
    v1.3.0΁ͷϚΠάϨʔγϣϯॲཧ
    24
    https://github.com/cocoa-mhlw/cocoa/blob/release_1_4_0/Covid19Radar/Covid19Radar/Services/Migration/Migrator_1_3_0.cs
    private void MigrateDateTimeToEpoch(string dateTimeKey, string epochKey, TimeSpan differential)


    {


    string dateTimeStr = _preferencesService.GetValue(dateTimeKey, DateTime.UtcNow.ToString());


    DateTime dateTime;


    try


    {


    dateTime = DateTime.SpecifyKind(DateTime.Parse(dateTimeStr) + differential, DateTimeKind.Utc);


    }


    catch (FormatException exception)


    {


    _loggerService.Exception($"Parse dateTime FormatException occurred. {dateTimeStr}", exception);


    dateTime = DateTime.UtcNow;


    }


    _preferencesService.SetValue(epochKey, dateTime.ToUnixEpoch());


    _preferencesService.RemoveValue(dateTimeKey);


    }


    View Slide

  25. ϚΠάϨʔγϣϯʢMigrationʣॲཧ
    όʔδϣϯؒͰҟͳΔσʔλܗࣜΛҠߦ͢Δ
    • σʔλܗࣜͷҟͳΔ࣌ظ

    • v1.0.0 - v1.2.1

    • v1.2.2 - v1.2.6
    25

    View Slide

  26. v1.0.0-v1.2.1
    • ΞϓϦͷσʔλ͸Application.Propertiesʹอଘ

    • Xamarin.Forms͕༻ҙ͍ͯ͠ΔӬଓԽํࣜ

    • ࣮ମϑΝΠϧ͸Binary XMLܗࣜ
    26

    View Slide

  27. Application.Propertiesͷ՝୊
    • Application.Properties͸εϨουηʔϑͰ͸ͳ͍

    • ෳ਺εϨου͔ΒΞΫηε͢Δͱσʔλ͕յΕΔ͜ͱ͕͋Δ

    • COCOA ಥવॳظԽ͞ΕΔ໰୊

    https://github.com/cocoa-mhlw/cocoa/issues/16
    27

    View Slide

  28. v1.2.2-v1.2.5
    • ΞϓϦͷσʔλ͸ϓϥοτϑΥʔϜݻ༗ͷܗࣜʹอଘ

    • AndroidͰ͸`SharedPreferences`

    • iOSͰ͸`NSUserDefaults`

    • Application.Properties͔ΒͷҠߦʢϚΠάϨʔγϣϯʣ͕௥Ճ
    28

    View Slide

  29. v1.2.2-v1.2.5ͷ՝୊
    ෳ਺ΫϥεʹϚΠάϨʔγϣϯॲཧ͕෼ࢄ͍ͯͨ͠
    • ར༻ن໿ͱϓϥΠόγʔϙϦγʔͷ߹ҙ೔࣌

    https://github.com/cocoa-mhlw/cocoa/blob/release_1_2_5/Covid19Radar/
    Covid19Radar/Services/TermsUpdateService.cs

    • ར༻։࢝೔ɾར༻ن໿ͱϓϥΠόγʔϙϦγʔͷ߹ҙϑϥά

    https://github.com/cocoa-mhlw/cocoa/blob/release_1_2_5/Covid19Radar/
    Covid19Radar/Services/UserDataService.cs

    • ઀৮ه࿥

    https://github.com/cocoa-mhlw/cocoa/blob/release_1_2_5/Covid19Radar/
    Covid19Radar/Services/ExposureNoti
    fi
    cationService.cs

    29

    View Slide

  30. v1.2.2-v1.2.5ͷ՝୊
    ϓϥοτϑΥʔϜݻ༗ͷҠߦॲཧΛαʔυύʔςΟϥΠϒϥϦΛվม͢ΔܗͰهड़͍ͯͨ͠
    30
    namespace Xamarin.ExposureNotifications


    {


    public static partial class ExposureNotification


    {


    private static readonly string[] OldWorkNames = { "exposurenotification" }; // Array of old work-name.


    private static readonly string CurrentWorkName = "cocoaexposurenotification"; // Current work-name. (changed policy from `replace` to `keep`)


    // Schedule background work (Customization by COCOA)


    static Task PlatformScheduleFetch()


    {


    CancelOldWork();


    var workRequest = CreatePeriodicWorkRequest();


    EnqueueUniquePeriodicWork(workRequest);


    return Task.CompletedTask;


    }


    private static void CancelOldWork()


    {


    var workManager = WorkManager.GetInstance(Essentials.Platform.AppContext);


    foreach (var oldWorkName in OldWorkNames)


    {


    workManager.CancelUniqueWork(oldWorkName);


    }


    }


    }


    }


    }
    https://github.com/cocoa-mhlw/cocoa/blob/release_1_2_5/Covid19Radar/Xamarin.ExposureNoti
    fi
    cation/ExposureNoti
    fi
    cation.customize.android.cs

    View Slide

  31. v1.2.6 ϚΠάϨʔγϣϯͷ࢓૊ΈΛಋೖ
    ෼ࢄͤͣ͞ɺҰΧॴͰॲཧ͢Δ
    • fromVersion → toVersionͰඞཁͳϚΠάϨʔγϣϯΛॱ࣮࣍ߦ

    • fromVersion: ઃఆʹه࿥͞ΕΔʢ·ͨ͸ਪଌ͢ΔʣΞϓϦͷόʔδϣϯ

    • toVersion: ݱࡏͷΞϓϦͷόʔδϣϯ
    31
    Add feature migrations mechanism #165

    https://github.com/cocoa-mhlw/cocoa/pull/165

    View Slide

  32. v1.2.6 ϦϦʔε


    2021/09/08
    32

    View Slide

  33. ͜ͷॲཧ͸ͳʹʁ
    **v1.3.0** ΁ͷϚΠάϨʔγϣϯॲཧ
    33
    https://github.com/cocoa-mhlw/cocoa/blob/release_1_4_0/Covid19Radar/Covid19Radar/Services/Migration/Migrator_1_3_0.cs
    private void MigrateDateTimeToEpoch(string dateTimeKey, string epochKey, TimeSpan differential)


    {


    string dateTimeStr = _preferencesService.GetValue(dateTimeKey, DateTime.UtcNow.ToString());


    DateTime dateTime;


    try


    {


    dateTime = DateTime.SpecifyKind(DateTime.Parse(dateTimeStr) + differential, DateTimeKind.Utc);


    }


    catch (FormatException exception)


    {


    _loggerService.Exception($"Parse dateTime FormatException occurred. {dateTimeStr}", exception);


    dateTime = DateTime.UtcNow;


    }


    _preferencesService.SetValue(epochKey, dateTime.ToUnixEpoch());


    _preferencesService.RemoveValue(dateTimeKey);


    }


    View Slide

  34. v1.2.6 ·Ͱͷ՝୊
    ೔࣌৘ใͷอଘܗࣜ
    • v1.2.6࣌఺ͰɺCOCOAʹ͸4ͭͷ೔࣌৘ใΛอଘ

    • ࢖༻։࢝೔࣌ʢStartDateTimeʣ

    • ར༻ن໿ʹ߹ҙͨ͠೔࣌ʢTermsOfServiceLastUpdateDateTimeʣ

    • ϓϥΠόγʔϙϦγʔʹ߹ҙͨ͠೔࣌
    ʢPrivacyPolicyLastUpdateDateTimeʣ

    • ઀৮֬ೝͨ͠਍அΩʔͷ࠷৽ͷ࡞੒೔ʢLastProcessTekTimestampʣ
    34
    https://cocoa-mhlw.github.io/cocoa/docs/appendix/preference_speci
    fi
    cation/#v122---v126

    View Slide

  35. จࣈྻͱͯ͠อଘ͞Εͨ೔࣌৘ใ
    • LastProcessTekTimestampΛআ͍ͨ3ͭͷ೔࣌৘ใΛจࣈྻͱͯ͠อଘ

    • ࢖༻։࢝೔࣌ʢStartDateTimeʣ

    • ར༻ن໿ʹ߹ҙͨ͠೔࣌ʢTermsOfServiceLastUpdateDateTimeʣ

    • ϓϥΠόγʔϙϦγʔʹ߹ҙͨ͠೔࣌
    ʢPrivacyPolicyLastUpdateDateTimeʣ

    • ઀৮֬ೝͨ͠਍அΩʔͷ࠷৽ͷ࡞੒೔ʢLastProcessTekTimestampʣ
    35
    https://cocoa-mhlw.github.io/cocoa/docs/appendix/preference_speci
    fi
    cation/#v122---v126

    View Slide

  36. ೔࣌จࣈྻ͸ϑΥʔϚοτࢦఆͳ͠ͷDateTime.ToString()ͷ݁Ռ
    DateTime.ToString()ͷ݁Ռ͸࣮ߦ؀ڥʢݴޠɾϩέʔϧʣʹґଘ͢Δ
    36
    using System;


    using System.Globalization;




    public class Program


    {


    public static void Main()


    {


    CultureInfo culture = CultureInfo.CreateSpecificCulture("ja-JP");


    CultureInfo.CurrentCulture = culture;


    var datetime = new DateTime(2021, 12, 11);




    Console.WriteLine(datetime.ToString());


    }


    }
    2021/12/11 0:00:00

    View Slide

  37. ֤ϩέʔϧͰͷDateTime.ToString()ͷ࣮ߦ݁Ռ
    2021೥12݄11೔ new DateTime(2021, 12, 11).ToString()
    • ೔ຊޠ-೔ຊʢja-JPʣ

    → 2021/12/11 0:00:00

    • ӳޠ-ΞϝϦΧ߹ऺࠃʢen-USʣ

    → 12/11/2021 12:00:00 AM

    • ӳޠ-ӳࠃʢen-GBʣ

    → 11/12/2021 00:00:00

    • ӳޠ-೔ຊʢen-JPʣ

    → 12/11/2021 12:00:00 AM
    37

    View Slide

  38. ʮӳޠɾӳࠃʢen-GBʣʯʹઃఆ͍ͯ͠Δਓ͕ɺ


    ೔ຊʹ౸ண͙ͯ͢͠ʹCOCOAΛΠϯετʔϧɻ


    ར༻։࢝ޙɺઃఆΛʮӳޠɾ೔ຊʢen-JPʣʯʹ੾Γସ͑ͨΒʁ
    38

    View Slide

  39. en-GBͰอଘ͞ΕΔ೔࣌จࣈྻ
    39
    "11/12/2021 00:00:00"

    View Slide

  40. en-JPͰղऍ͞ΕΔ೔࣌
    40
    using System;


    using System.Globalization;




    public class Program


    {


    public static void Main()


    {


    CultureInfo culture = CultureInfo.CreateSpecificCulture("en-JP");


    CultureInfo.CurrentCulture = culture;


    var datetime = DateTime.Parse("11/12/2021 00:00:00");




    Console.WriteLine(datetime.ToString());


    }


    }
    "11/12/2021 12:00:00 AM"

    View Slide

  41. ೔࣌৘ใͱͯ͠ղऍͰ͖ͳ͍έʔε
    41
    using System;


    using System.Globalization;




    public class Program


    {


    public static void Main()


    {


    CultureInfo culture = CultureInfo.CreateSpecificCulture("en-JP");


    CultureInfo.CurrentCulture = culture;


    var datetime = DateTime.Parse("25/12/2021 00:00:00");




    Console.WriteLine(datetime.ToString());


    }


    }
    Unhandled exception. System.FormatException: String '25/12/2021 00:00:00' was not recognized as a valid DateTime.


    at System.DateTime.Parse(String s)


    at Program.Main()

    View Slide

  42. ؔ࿈͢Δ՝୊
    • [Android] ୺຤ͷݴޠΛมߋޙʮϓϥΠόγʔϙϦγʔͷվఆʯ͕࠶දࣔ͞Ε
    Δ

    https://github.com/cocoa-mhlw/cocoa/issues/49

    • ֤छ೔෇͕ϩέʔϧґଘͷϑΥʔϚοτͰอଘ͞ΕΔ

    https://github.com/cocoa-mhlw/cocoa/issues/51

    • [iOS] ར༻։࢝ޙɺ୺຤ϩέʔϧΛมߋ͢Δͱ࢖༻։࢝೔͕Ϧηοτ͞Εଓ͚
    Δ

    https://github.com/cocoa-mhlw/cocoa/issues/124
    42

    View Slide

  43. v1.3.0ͷϚΠάϨʔγϣϯॲཧ
    จࣈྻͷ೔࣌৘ใΛUNIX Epoch΁ม׵͢Δ
    43
    https://github.com/cocoa-mhlw/cocoa/blob/release_1_4_0/Covid19Radar/Covid19Radar/Services/Migration/Migrator_1_3_0.cs
    public Task ExecuteAsync()


    {


    if (_preferencesService.ContainsKey(START_DATETIME))


    {


    MigrateDateTimeToEpoch(START_DATETIME, PreferenceKey.StartDateTimeEpoch, TimeSpan.Zero);


    }


    if (_preferencesService.ContainsKey(TERMS_OF_SERVICE_LAST_UPDATE_DATETIME))


    {


    MigrateDateTimeToEpoch(


    TERMS_OF_SERVICE_LAST_UPDATE_DATETIME,


    PreferenceKey.TermsOfServiceLastUpdateDateTimeEpoch,


    -TIME_DIFFERENCIAL_JST_UTC


    );


    }


    if (_preferencesService.ContainsKey(PRIVACY_POLICY_LAST_UPDATE_DATETIME))


    {


    MigrateDateTimeToEpoch(


    PRIVACY_POLICY_LAST_UPDATE_DATETIME,


    PreferenceKey.PrivacyPolicyLastUpdateDateTimeEpoch,


    -TIME_DIFFERENCIAL_JST_UTC


    );


    }


    return Task.CompletedTask;


    }


    View Slide

  44. ͜ͷॲཧ͸ͳʹʁ
    จࣈྻͷ೔࣌৘ใΛUNIX Epoch΁ม׵͢Δ
    44
    https://github.com/cocoa-mhlw/cocoa/blob/release_1_4_0/Covid19Radar/Covid19Radar/Services/Migration/Migrator_1_3_0.cs
    private void MigrateDateTimeToEpoch(string dateTimeKey, string epochKey, TimeSpan differential)


    {


    string dateTimeStr = _preferencesService.GetValue(dateTimeKey, DateTime.UtcNow.ToString());


    DateTime dateTime;


    try


    {


    dateTime = DateTime.SpecifyKind(DateTime.Parse(dateTimeStr) + differential, DateTimeKind.Utc);


    }


    catch (FormatException exception)


    {


    _loggerService.Exception($"Parse dateTime FormatException occurred. {dateTimeStr}", exception);


    dateTime = DateTime.UtcNow;


    }


    _preferencesService.SetValue(epochKey, dateTime.ToUnixEpoch());


    _preferencesService.RemoveValue(dateTimeKey);


    }


    View Slide

  45. ো֐͸ɺͳͥى͖ͨͷ͔
    45

    View Slide

  46. ͳͥ͜ͷίʔυΛॻ͍ͨͷ͔
    46
    https://github.com/cocoa-mhlw/cocoa/blob/release_1_4_0/Covid19Radar/Covid19Radar/Services/Migration/Migrator_1_3_0.cs
    private void MigrateDateTimeToEpoch(string dateTimeKey, string epochKey, TimeSpan differential)


    {


    string dateTimeStr = _preferencesService.GetValue(dateTimeKey, DateTime.UtcNow.ToString());


    DateTime dateTime;


    try


    {


    dateTime = DateTime.SpecifyKind(DateTime.Parse(dateTimeStr) + differential, DateTimeKind.Utc);


    }


    catch (FormatException exception)


    {


    _loggerService.Exception($"Parse dateTime FormatException occurred. {dateTimeStr}", exception);


    dateTime = DateTime.UtcNow;


    }


    _preferencesService.SetValue(epochKey, dateTime.ToUnixEpoch());


    _preferencesService.RemoveValue(dateTimeKey);


    }


    View Slide

  47. ࣌ࠩิਖ਼ͷཁ݅
    • ೔࣌৘ใʢDateTimeʣͷจࣈྻʹ͸λΠϜκʔϯؚ͕·Ε͍ͯͳ͍ɻ

    ͔͠͠ɺར༻ن໿ɾϓϥΠόγʔϙϦγʔͷಉҙ೔࣌ʹ͍ͭͯ͸JSTͱͯ͠औΓѻ͏ඞཁ͕͋Δ

    • ࢖༻։࢝೔࣌ʢStartDateTimeʣ - UTC

    • ར༻ن໿ʹ߹ҙͨ͠೔࣌ʢTermsOfServiceLastUpdateDateTimeʣ - JST

    • ϓϥΠόγʔϙϦγʔʹ߹ҙͨ͠೔࣌ʢPrivacyPolicyLastUpdateDateTimeʣ - JST

    • ։ൃνʔϜΑΓࢦఠΛड͚ͯରԠ

    https://github.com/cocoa-mhlw/cocoa/commit/
    2b7b19de75b42e44cb1bb1c87406c99af9bd7754#di
    ff
    -180bad4c321871e2b4bf1cd58ce78d304
    0ccd6a64ec0937fd84e0b3514a00cc5
    47

    View Slide

  48. ͳͥλΠϜκʔϯͷิਖ਼ʹ

    ՃݮࢉΛ༻͍ͨͷ͔
    48

    View Slide

  49. ೖྗจࣈྻʹର͢Δೝࣝͷ؁͞
    • DateTimeͷܭࢉͰʢԼݶ஋ΛԼճΔɾ্ݶ஋Λ্ճΔʣͱ͖ʹྫ֎͕ൃੜ͢
    Δͱ͍͏஌͕ࣝෆ଍͍ͯͨ͠

    • ೖྗ͞ΕΔ஋ʹԼݶ஋ʢ0001/01/01 00:00:00ʣ͕ଘࡏ͢Δͱ͍͏ೝ͕ࣝෆ଍
    ͍ͯͨ͠
    49

    View Slide

  50. ݕ౼ͨ͠ࣄ߲
    DateTime.ToUniversalTime()
    • DateTime.ToUniversalTime()͸ɺ୺຤ͷϩέʔϧʹઃఆ͞Ε͍ͯΔ஍ҬͷλΠ
    ϜκʔϯΛʮϩʔΧϧλΠϜʢLocalʣʯͱͯ͠ɺ࣌ࠩͷิਖ਼Λߦ͏

    • ࠓճͷ৔߹ɺDateTimeͷݩʹͳΔจࣈྻʹλΠϜκʔϯͷ৘ใ͸ͳ͍ɻͦͷ
    ্ͰλΠϜκʔϯΛݻఆʢJST·ͨ͸UTCʣͯ࣌ࠩ͠Λิਖ਼͢Δඞཁ͕͋Δ

    • ୺຤ʹઃఆ͞Ε͍ͯΔϩέʔϧ͕ʮ೔ຊʢJSTʣʯͰ͋Δอূ͸ͳ͍
    50

    View Slide

  51. ݕ౼ͨ͠ࣄ߲
    TimeZoneInfo.ConvertTimeToUtc
    • ConverTimeToUtcΛ࣮ߦ͢Δ্ͰඞཁͳʮλΠϜκʔϯʢTimeZoneInfoʣʯ
    Λऔಘ͢Δࡍʹ༻͍ΔTimeZoneInfo.FindSystemTimeZoneByIdʹࢦఆ͢Δ஋
    ͕ɺϓϥοτϑΥʔϜʹΑͬͯҟͳΔɻ

    • WindowsͰ͸ "Tokyo Standard Time" ← MicrosoftެࣜυΩϡϝϯτͰ঺հ

    • LinuxͰ͸"Asia/Tokyo" ← Xamarin͸ʢʁʣͪ͜Β
    51
    ϓϥοτϑΥʔϜ͝ͱͷڍಈͷҧ͍͕ɺར༻Λسආ͢ΔཁҼʹͳͬͨ

    View Slide

  52. ೖྗจࣈྻʹର͢Δೝࣝͷ؁͞
    • DateTimeͷܭࢉͰʢԼݶ஋ΛԼճΔɾ্ݶ஋Λ্ճΔʣͱ͖ʹྫ֎͕ൃੜ͢
    Δͱ͍͏஌͕ࣝෆ଍͍ͯͨ͠

    • ೖྗ͞ΕΔ஋ͷൣғʹԼݶ஋ʢ0001/01/01 00:00:00ʣ͕ଘࡏ͢Δͱ͍͏ೝࣝ
    ͕ෆ଍͍ͯͨ͠
    52

    View Slide

  53. Ұ౓͸߹ҙ͠ͳ͍ͱΞϓϦ͕ར༻Ͱ͖ͳ͍
    • ࢖༻։࢝೔࣌ʢStartDateTimeʣ - UTC

    • ར༻ن໿ʹ߹ҙͨ͠೔࣌ʢTermsOfServiceLastUpdateDateTimeʣ - JST

    • ϓϥΠόγʔϙϦγʔʹ߹ҙͨ͠೔࣌
    ʢPrivacyPolicyLastUpdateDateTimeʣ - JST
    53

    View Slide

  54. ͳͥɺར༻ن໿߹ҙ೔͕


    0001/01/01 00:00:00


    ʹͳΔͷ͔
    54

    View Slide

  55. v1.2.2ͷϚΠάϨʔγϣϯ
    55
    private async Task MigrateTermAsync(TermsType termsType, bool isAgree)


    {


    var applicationPropertyKey = termsType == TermsType.TermsOfService ?


    APPLICATION_PROPERTY_TERMS_OF_SERVICE_LAST_UPDATE_DATE_KEY : APPLICATION_PROPERTY_PRIVACY_POLICY_LAST_UPDATE_DATE_KEY;


    var preferenceKey = termsType == TermsType.TermsOfService ?


    PREFERENCE_KEY_TERMS_OF_SERVICE_LAST_UPDATE_DATETIME : PREFERENCE_KEY_PRIVACY_POLICY_LAST_UPDATE_DATETIME;


    if (_preferencesService.ContainsKey(applicationPropertyKey))


    {


    return;


    }


    if (isAgree)


    {


    if (_applicationPropertyService.ContainsKey(applicationPropertyKey))


    {


    var lastUpdateDate = _applicationPropertyService.GetProperties(applicationPropertyKey).ToString();


    _preferencesService.SetValue(preferenceKey, lastUpdateDate);


    }


    else


    {


    _preferencesService.SetValue(preferenceKey, new DateTime().ToString());


    }


    }


    await _applicationPropertyService.Remove(applicationPropertyKey);


    }


    https://github.com/cocoa-mhlw/cocoa/blob/release_1_4_0/Covid19Radar/Covid19Radar/Services/Migration/Migrator_1_2_2.cs

    https://github.com/cocoa-mhlw/cocoa/blob/release_1_2_5/Covid19Radar/Covid19Radar/Services/TermsUpdateService.cs

    View Slide

  56. ೺Ѳ͍ͯ͠ͳ͔ͬͨมߋ
    • ར༻ن໿ɺϓϥΠόγʔϙϦγʔͷ߹ҙ೔࣌Λه࿥͢ΔΑ͏ʹͳͬͨͷ͸
    v1.2.0ʢ2020/12/03ϦϦʔεʣ͔Β

    • ϓϥΠόγʔϙϦγʔɺར༻ن໿ͷվగ͕͋ͬͨ

    • v1.1.5Ҏલ͸߹ҙ͔ͨ͠Ͳ͏͔ʢIsOptined, IsPolicyAcceptedʣͷΈ؅ཧ
    56
    ઀৮֬ೝΞϓϦʮCOCOAʯͷमਖ਼൛ʢʮ1.2.0ʯʣͷ഑෍Λ։࢝͠·ͨ͠ɻ

    https://www.mhlw.go.jp/stf/newpage_15244.html

    View Slide

  57. v1.2.2ͷϚΠάϨʔγϣϯ
    v1.1.5Ҏલ͔ΒͷϚΠάϨʔγϣϯͰൃੜ
    57
    private async Task MigrateTermAsync(TermsType termsType, bool isAgree)


    {


    var applicationPropertyKey = termsType == TermsType.TermsOfService ?


    APPLICATION_PROPERTY_TERMS_OF_SERVICE_LAST_UPDATE_DATE_KEY : APPLICATION_PROPERTY_PRIVACY_POLICY_LAST_UPDATE_DATE_KEY;


    var preferenceKey = termsType == TermsType.TermsOfService ?


    PREFERENCE_KEY_TERMS_OF_SERVICE_LAST_UPDATE_DATETIME : PREFERENCE_KEY_PRIVACY_POLICY_LAST_UPDATE_DATETIME;


    if (_preferencesService.ContainsKey(applicationPropertyKey))


    {


    return;


    }


    if (isAgree)


    {


    if (_applicationPropertyService.ContainsKey(applicationPropertyKey))


    {


    var lastUpdateDate = _applicationPropertyService.GetProperties(applicationPropertyKey).ToString();


    _preferencesService.SetValue(preferenceKey, lastUpdateDate);


    }


    else


    {


    _preferencesService.SetValue(preferenceKey, new DateTime().ToString());


    }


    }


    await _applicationPropertyService.Remove(applicationPropertyKey);


    }


    https://github.com/cocoa-mhlw/cocoa/blob/release_1_4_0/Covid19Radar/Covid19Radar/Services/Migration/Migrator_1_2_2.cs

    https://github.com/cocoa-mhlw/cocoa/blob/release_1_2_5/Covid19Radar/Covid19Radar/Services/TermsUpdateService.cs

    View Slide

  58. ͳͥ

    0001/01/01 00:00:00 ͕

    ͍·ͩʹ࢒͍ͬͯΔͷ͔ʁ
    58

    View Slide

  59. v1.2.0Ҏ߱ɺϓϥΠόγʔϙϦγʔͱ

    ར༻ن໿͕վగ͞Ε͍ͯΔͷ͔ͩΒɺ

    ͦͷ࣌఺ͷ೔෇ʹͳ͍ͬͯΔ͸ͣͰ͸ʁ
    59

    View Slide

  60. ར༻ن໿ͷ࠶ಉҙϓϩηε͕࢖ΘΕͨʢදࣔ͞Εͨʣ͜ͱ͕ͳ͍
    60
    {


    "privacy_policy" : {


    "text" : "We will retain in the management system the processing numbers required to register people who have tested positive for COVID-19 in COCOA
    to respond to inquiries. We have revised the Privacy Policy due to this. Please confirm the revised content from the link below.",


    "update_date" : "2021/12/01 13:00:00"


    }


    }


    {


    "terms_of_service" : {


    "text": "",


    "update_date" : ""


    },


    "privacy_policy" : {


    "text" : "We will retain in the management system the processing numbers required to register people who have tested positive for COVID-19 in COCOA
    to respond to inquiries. We have revised the Privacy Policy due to this. Please confirm the revised content from the link below.",


    "update_date" : "2021/12/01 13:00:00"


    }


    }


    v1.1.5Ͱར༻ن໿ʹ߹ҙ͍ͯͨ͠৔߹ɺ߹ҙ೔࣌͸ߋ৽͞Εͳ͍ʢ0001/01/01 00:00:00ͷ··ʣ

    View Slide

  61. ো֐͸ɺͳͥى͖ͨͷ͔


    ·ͱΊ
    61

    View Slide

  62. ՝୊ʹର͢Δೝࣝͷ؁͞ɾ࣮ྗෆ଍
    • λΠϜκʔϯิਖ਼ʢJST͔ΒUTCʣํ๏ͷෆద੾ͳબ୒

    • ݴޠʢC#ʣ࢓༷΁ͷཧղ͕ෆे෼ͳ··࣮૷Λͨ͠

    • աڈόʔδϣϯͷ࢓༷ͷௐ͕ࠪෆ଍͍ͯͨ͠
    62
    ΞΫγσϯτϨϙʔτʮv1.4.0ϦϦʔεͰൃੜͨ͠ো֐ʹ͍ͭͯʯ #544

    https://github.com/cocoa-mhlw/cocoa/pull/544

    View Slide

  63. ARIYAMA Keiji - σδλϧிAndroidʢΞϓϦʣΤϯδχΞ / ༗ݶձࣾγʔϦε୅ද
    COCOA 1.4.0 ো֐͸

    ͳͥى͖ͨͷ͔
    ୭͔ͷ͍ͤʹ͍͕ͨ͠
    ࣗ෼ͷإ͔͠ࢥ͍ු͔͹ͳ͍
    63

    View Slide

  64. ࠓޙͷରԠ
    • ϚΠάϨʔγϣϯॲཧΛվળ͢Δ

    https://github.com/cocoa-mhlw/cocoa/issues/520

    • ΞΫγσϯτϨϙʔτΛॻ͘

    https://github.com/cocoa-mhlw/cocoa/pull/544

    • ࠶ൃ๷ࢭࡦͷݕ౼ɾ࣮ࢪ
    64

    View Slide

  65. ݕ౼தͷ࠶ൃ๷ࢭࡦ
    ো֐ൃੜ࣌ͷӨڹΛ௿ݮ͢Δํࡦ΋ؚΉ
    • ೔࣌৘ใͷऔΓѻ͍ʹ͍ͭͯఆΊΔ

    • ಺෦Ͱ͸UNIX Epochͱͯ͠อଘ͢Δɻ·ͨɺจࣈྻදݱΛRFC 3339ʹ౷
    Ұ͢Δ͜ͱͰϩέʔϧͷҧ͍ʹΑΔڍಈͷҧ͍Λٵऩ͢Δ

    • ϢχοτςετΛ੔උ͢ΔɻಛʹίʔυΧόϨοδΛܭଌ͢Δ͜ͱͰɺϢ
    χοτςετ͕ΧόʔͰ͖͍ͯͳ͍ͱ͜ΖΛՄࢹԽ͢Δ

    • ϩʔϦϯάΞοϓσʔτʢஈ֊తͳެ։ʣΛ࣮ࢪ͢Δ͜ͱͰɺϦϦʔεΛதࢭ
    Ͱ͖ΔΑ͏ʹ͢Δ
    65

    View Slide

  66. ݕ౼தͷ࠶ൃ๷ࢭࡦ
    ো֐ൃੜ࣌ͷӨڹΛ௿ݮ͢Δํࡦ΋ؚΉ
    • ਖ਼ࣜϦϦʔεલʹBeta൛Λ഑෍͢Δ͜ͱͰɺΑΓଟ͘ͷར༻ऀɺ୺຤Ͱςετ
    Ͱ͖ΔΑ͏ʹ͢Δ

    • ϦϦʔε༧ఆ೔ɾϦϦʔεঢ়گʢϩʔϦϯάΞοϓσʔτؚΉʣΛɺ͋Β͔͡
    ΊGitHubͳͲͰެද͠ɺެ։࣌ͷ໨ͷ਺Λ૿΍͢͜ͱͰো֐ͷൃੜΛ͍ͪૣ
    ͘ݕग़͢Δ

    • ϦϦʔε࣌ظʢϩʔϦϯάΞοϓσʔτؚ࣌Ήʣʹ͸ɺSNSͷ؍ଌΛΦϖϨʔ
    γϣϯͱͯ͠ߦ͏
    66

    View Slide

  67. ݕ౼͍ͯ͠ͳ͍࠶ൃ๷ࢭࡦ
    • ίʔυͷऔΓࠐΈʹ౰ͨͬͯ͸ඞͣμϒϧνΣοΫɺՄೳͰ͋Ε͹τϦϓϧ
    νΣοΫΛߦ͏
    67

    View Slide

  68. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠
    68

    View Slide