├── Android_Testing_BC_1 ├── README.md └── images │ ├── droidkaigi_google_play.png │ ├── スクリーンショット 2016-03-22 17.07.57.png │ ├── スクリーンショット 2016-03-22 18.25.27.png │ ├── スクリーンショット 2016-03-23 1.07.50.png │ └── スクリーンショット 2016-03-23 1.08.10.png ├── Androidエンジニア_デザイン部_#1 ├── README.md └── images │ ├── dd.png │ ├── font.png │ ├── show_l.png │ └── view.png ├── DroidKaigi_ランチタイムLT会_Vol.1 ├── README.md └── images │ ├── App_usage.png │ └── Effects.png ├── Flutter_Meetup_Tokyo_1 ├── README.md ├── flutter_plugin.png └── pub.png ├── Flutter_Meetup_Tokyo_2 └── README.md ├── Gunosy_beer ├── README.md └── images │ ├── app.png │ ├── image.png │ └── mercari.png ├── Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka ├── README.md ├── mb.png ├── mb2.png ├── permission.png └── slice.png ├── README.md ├── Roppongi.aar_2 └── README.md ├── Shibuya.apk2 └── README.md ├── Shibuya.apk51 ├── README.md └── images │ ├── image.png │ ├── image2.png │ ├── image3.png │ ├── image4.png │ ├── image5.png │ └── image6.png ├── Shibuya.apk_10 └── README.md ├── Shibuya.apk_4 └── README.md ├── Shibuya_apk30 ├── README.md └── images │ ├── image1.png │ ├── image2.png │ ├── image3.png │ ├── image4.png │ ├── image5.png │ ├── image6.png │ └── image7.png ├── Souzoh_Android_Talk_2 ├── Contributeしてない俺がDroidKaigiアプリについてゴニョゴニョ話す会.md ├── DroidKaigi発表 + 一部運営振り返り.md └── images │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ └── 6.png ├── kyobashi.dex_2 ├── README.md └── images │ └── droidkaigi.png ├── kyobashi.dex_3 ├── README.md └── arts │ ├── gradle-slack-plugin_and_gradle-version-plugin_and_ci_and_slack.png │ ├── gradle-version-plugin.png │ ├── gralde-zundokokiyoshi-plugin.png │ └── gralde-zundokokiyoshi-plugin_and_ci.png ├── note_engineer_meetup_1 ├── README.md └── images │ ├── app.png │ ├── crash_report.png │ ├── o.png │ ├── p.png │ └── pp.png ├── note_社内LT_2020-06-26 ├── README.md └── images │ └── workflow.png ├── otemachi_apk_2 ├── README.md └── images │ ├── role.png │ ├── role_req1.png │ ├── role_req2.png │ └── setting_panel.png ├── potatotips_23 ├── README.md └── note.md ├── potatotips_52 ├── README.md └── images │ ├── non-sdk-list.png │ ├── non-sdk.png │ ├── okhttp.png │ ├── osu.png │ ├── result-1.png │ ├── result-2.png │ └── result-3.png ├── retty_tech_cafe_6 └── README.md ├── schoo_2015_10_29 ├── README.md └── links.md ├── まったりAndroid Framework Code Reading_2 ├── README.md └── note.md ├── 俺的 2017年のAndroidを振り返る └── README.md ├── 第1回スタートアップAndroid勉強会 ├── README.md └── memo.md └── 開発×テスト LT会 - vol.2 #devtestlt ├── README.md └── images ├── file_null.png └── test_splitting.png /Android_Testing_BC_1/README.md: -------------------------------------------------------------------------------- 1 | # DroidKaigiアプリをSpoonで全画面スクショしてみた 2 | 3 | 4 | # Android Testing Bootcamp #1 5 | 6 | 7 | # Do you like Test?? 8 | 9 | 10 | # Do you like Android Test?? 11 | 12 | # Screenshots Test 13 | 14 | # Spoon + Espresso 15 | 16 | ## Spoon?? 17 | 18 | * “Using the application APK and instrumentation APK,Spoon runs the tests on multiple devices simultaneously.“ 19 | 20 | 21 | ## Spoon?? 22 | 23 | * “Once all tests have completed a static HTML summary is generatedwith detailed information about each device and test.“ 24 | 25 | 26 | ## Spoon?? 27 | 28 | * Spoon.screenshot(activity, "after_login"); 29 | 30 | 31 | ## Spoon 32 | 33 | * https://github.com/square/spoon 34 | 35 | ## Espresso 36 | 37 | * https://code.google.com/p/android-test-kit/wiki/Espresso 38 | 39 | ## Spoon Gradle Plugin?? 40 | 41 | * “Gradle plugin for Spoon. Allows you to run spoon with almost no effort under new Android build system.“ 42 | 43 | 44 | ## Spoon Gradle Plugin?? 45 | 46 | * gradle spoon 47 | 48 | ## Spoon Gradle Plugin?? 49 | 50 | ```gradle 51 | gradle spoon 52 | ``` 53 | 54 | ## Spoon Gradle Plugin 55 | 56 | * https://github.com/stanfy/spoon-gradle-plugin 57 | 58 | 59 | ## EspressoSpoonSample 60 | 61 | * https://github.com/operando/EspressoSpoonSample 62 | 63 | 64 | ## Demo 65 | 66 | 67 | ## Demo 68 | 69 | ```gradle 70 | gradle spoonDebugAndroidTestLarge 71 | ``` 72 | 73 | # DroidKaigi 2016 official Android app 74 | 75 | * https://github.com/konifar/droidkaigi2016 76 | 77 | 78 | # DroidKaigi 2016 official Android app 79 | 80 | ![droidkaigi_google_play](./images/droidkaigi_google_play.png) 81 | 82 | 83 | # Number of screens 84 | 85 | * ?? 86 | 87 | # 結論 88 | 89 | * そんなに難しくないよー 90 | 91 | # Demo 92 | 93 | 94 | 95 | 96 | # Android Test Tips 97 | 98 | 99 | # Android Testing Support Library Release notes 100 | 101 | * https://google.github.io/android-testing-support-library/downloads/release-notes/index.html 102 | 103 | # Android Testing Support Library javadoc 104 | 105 | * http://developer.android.com/reference/android/support/test/package-summary.html 106 | 107 | # Android Testing Support Library javadoc 108 | 109 | * なんか最新じゃ無い気がする... 110 | * Espresso 2.2.2の内容が反映されてない疑惑... 111 | 112 | # Release notes 113 | 114 | * Espresso 2.2.2, Runner/Rules 0.5 (2016-02-22, silent release) 115 | 116 | 117 | # NavigationViewActions 118 | 119 | 120 | # NavigationViewActions 121 | 122 | * [Espresso] NavigationViewをNavigationViewActionsで操作してみようの話 123 | * http://qiita.com/operandoOS/items/05f650e7b7fe7e5189c2 124 | 125 | # NavigationViewActionsSample 126 | 127 | * https://github.com/operando/NavigationViewActionsSample 128 | 129 | # Demo 130 | 131 | 132 | ## Sponn Settings 133 | 134 | ```gradle 135 | spoon { 136 | debug true 137 | noAnimations true 138 | failIfNoDeviceConnected true 139 | adbTimeout 60 140 | } 141 | ``` 142 | 143 | ## 俺が考えた最強のBest Practice 144 | 145 | ### 画面表示ができればOK 146 | 147 | 画面表示までに全力を注ぐ 148 | 149 | Espressoで細かい操作はしない 150 | 151 | 152 | ### Espressoを最小限に使う 153 | 154 | あくまで最小限 155 | 156 | 最大限使わない 157 | 158 | 頑張らない 159 | 160 | 161 | ### createIntentパターンを使う 162 | 163 | Activity起動に必要な情報がわかりやすい 164 | 165 | 表示したい画面のIntentが大事 166 | 167 | 168 | ```java 169 | public class LoginSuccessActivity extends AppCompatActivity { 170 | 171 | private static final String EMAIL = "email"; 172 | 173 | public static Intent createIntent(Context context, String email) { 174 | Intent i = new Intent(context, LoginSuccessActivity.class); 175 | i.putExtra(EMAIL, email); 176 | return i; 177 | } 178 | } 179 | ``` 180 | 181 | 182 | ### 実機とエミュレータを使い分ける 183 | 184 | 実機は機種依存が分かる 185 | 186 | エミュレータは解像度が柔軟に変更できる 187 | 188 | 189 | ### 大雑把に確認する 190 | 191 | 厳密に結果を確認しない 192 | 193 | 表示するデータのこがわらない 194 | 195 | 196 | ### 全画面撮ろうとしない 197 | 198 | アプリの規模によっては全画面無理 199 | 200 | 全画面撮れても価値があるのか疑問 201 | 202 | 撮って価値ある画面に着目する 203 | 204 | 205 | ### 前提条件が厳しい画面は潔く諦める 206 | 207 | とにかく頑張らない 208 | 209 | 210 | ### とにかく頑張らない 211 | 212 | 気軽に楽しくがモットー 213 | 214 | ハマるな危険 = 頑張り過ぎちゃう 215 | 216 | 217 | ## 俺が考えた最強のBest Practice 218 | 219 | * 画面表示ができればOK 大事 220 | * Espressoを最小限に使う 221 | * createIntentパターンを使う 大事 222 | * 実機とエミュレータを使い分ける 大事 223 | * 大雑把に確認する 224 | * 全画面撮ろうとしない 225 | * 前提条件が厳しい画面は潔く諦める 大事 226 | * とにかく頑張らない 227 | 228 | ## Thanks! 229 | -------------------------------------------------------------------------------- /Android_Testing_BC_1/images/droidkaigi_google_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Android_Testing_BC_1/images/droidkaigi_google_play.png -------------------------------------------------------------------------------- /Android_Testing_BC_1/images/スクリーンショット 2016-03-22 17.07.57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Android_Testing_BC_1/images/スクリーンショット 2016-03-22 17.07.57.png -------------------------------------------------------------------------------- /Android_Testing_BC_1/images/スクリーンショット 2016-03-22 18.25.27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Android_Testing_BC_1/images/スクリーンショット 2016-03-22 18.25.27.png -------------------------------------------------------------------------------- /Android_Testing_BC_1/images/スクリーンショット 2016-03-23 1.07.50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Android_Testing_BC_1/images/スクリーンショット 2016-03-23 1.07.50.png -------------------------------------------------------------------------------- /Android_Testing_BC_1/images/スクリーンショット 2016-03-23 1.08.10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Android_Testing_BC_1/images/スクリーンショット 2016-03-23 1.08.10.png -------------------------------------------------------------------------------- /Androidエンジニア_デザイン部_#1/README.md: -------------------------------------------------------------------------------- 1 | # デザインの実装を解体する技術 2 | 3 | ## スライド 4 | 5 | * https://speakerdeck.com/operando/dezainfalseshi-zhuang-wojie-ti-suruji-shu 6 | 7 | ## (デザインを語る前に...) エンジニアなら実装できないとね!! 8 | 9 | 10 | ## デザインの実装を解体するとは? 11 | 12 | * 色んなアプリのデザイン・レイアウトがどのように組まれているのかを調べる 13 | 14 | 15 | ## 解体するために 16 | 17 | * 日頃から色んなアプリに触れる 18 | * 色んなジャンルのアプリに触れる 19 | * 解体道具をてなずける 20 | 21 | ## 話す内容は自身が作っていないアプリに
対してのアプローチ 22 | 23 | 24 | ## デザインの構造を解体する 25 | 26 | * Show layout bounds 27 | * レイアウトの境界を表示する 28 | * レイアウトの構造がなんとなくわかる 29 | 30 | 31 | ## Show layout bounds 32 | 33 | * ![](./images/show_l.png) 34 | 35 | 36 | ## Show layout bounds 37 | 38 | * adbから有効にする 39 | 40 | ```bash 41 | adb shell setprop debug.layout true 42 | ``` 43 | 44 | 45 | ## Show layout bounds 46 | 47 | * レイアウトの構造がなんとなくわかるので便利 48 | * でも隠れてるViewや細かい構造がわからない 49 | * Android Device MonitorのLayout Inspectorの便利! 50 | * https://developer.android.com/studio/profile/monitor.html 51 | * https://developer.android.com/studio/debug/layout-inspector.html 52 | 53 | 54 | ## デザインの構造を解体する 55 | 56 | * 画面の密度を変更する 57 | * 文字のサイズを変更する 58 | * あえてレイアウトが崩れそうなことをやってみる 59 | * 想定外の画面や文字サイズにどう対応しているか見る 60 | 61 | 62 | ## 画面の密度・文字のサイズを変更する 63 | 64 | * Accessibility → Font size → Largest 65 | * Accessibility → Display size → Largest 66 | 67 | or 68 | 69 | * Display → Font size → Largest 70 | * Display → Display size → Largest 71 | 72 | 73 | ## 画面の密度・文字のサイズを変更する 74 | 75 | ![](./images/dd.png) 76 | ![](./images/font.png) 77 | 78 | 79 | ## 画面の密度を変更する 80 | 81 | * adb shellからも変更できるよ! 82 | * 設定値の上限がないので、やばい世界が見れる 83 | * 下限値はある! → 72 84 | 85 | 86 | ## 画面の密度を変更する 87 | 88 | ```bash 89 | // 密度を変更する 90 | adb shell wm density 800 91 | 92 | // 元に戻す 93 | adb shell wm density reset 94 | ``` 95 | 96 | 97 | ## 文字のサイズを変更する 98 | 99 | * adb shellからも変更できるよ! 100 | * 設定値の上限がないので、やばい世界が見れる 101 | 102 | ```bash 103 | adb shell settings put system font_scale 1.3 104 | ``` 105 | 106 | 107 | ## 画面の密度・文字のサイズを変更する 108 | 109 | * 限界はない💪 110 | 111 | 112 | ## 画面の密度・文字のサイズを変更する 113 | 114 | * ただし壊れそう💖 115 | 116 | 117 | ## デザインの構造を解体する 118 | 119 | * View Hierarchyをdumpする 120 | * `adb shell dumpsys activity top` 121 | * dumpしたい画面を開いて実行 122 | 123 | 124 | ## dumpsys activity top 125 | 126 | ![](./images/view.png) 127 | 128 | 129 | ## dumpsys activity top 130 | 131 | * View.GONEとかで見れないViewもわかる 132 | * 動的にViewが変わったりしなければ丸見え 133 | * Viewのidがわかるのでゴニョゴニョできる 134 | * でも細かい属性の設定がわからない 135 | 136 | 137 | ## デザインの構造を解体する 138 | 139 | * apkを解体する 140 | * 最終手段? 💪 141 | * 最終兵器? 🔪 142 | 143 | 144 | ## apkを解体するツール 145 | 146 | * apktool ⚡ 147 | * https://ibotpeaches.github.io/Apktool/ 148 | * dex2ja 👹 149 | * https://github.com/pxb1988/dex2jar 150 | * aapt 🔥 151 | * Android Asset Packaging Tool 152 | * https://elinux.org/Android_aapt 153 | 154 | 155 | ## 端末からapkをさくっと引っこ抜く 156 | 157 | * 素晴らしい記事あります! 158 | * dumpsys activity activitiesとpecoでゴニョゴニョして端末からapkを簡単に引っこ抜く 159 | * https://qiita.com/operandoOS/items/6fa77037560e52d11352 160 | 161 | 162 | ## apkを解体するツール 163 | 164 | * 解体方法は… ね? 165 | 166 | 167 | ## 解体すると手に入るもの 168 | 169 | * リソース一式 170 | * レイアウトファイルも含む 171 | * jar 172 | * 難読化されてないと丸見え 173 | * 難読化怖くないだいじょうぶ 174 | 175 | 176 | ## 目的のレイアウトファイルを調べる その1 177 | 178 | * 前に紹介したdumpsys activity topでリソースIDの名前はわかる 179 | * あとはIDが使用されているレイアウトを調べるだけ 180 | * grepでもいいし、エディターの検索でもいい 181 | 182 | 183 | ## 目的のレイアウトファイルを調べる その2 184 | 185 | * リソースIDから調べる 186 | * jarをゴニョゴニョして見るとリソースIDがわかる 187 | * コード上のリソースIDを16進数に変換する 188 | * 元は10進数。方法は何でもいいので変換する 189 | * 16進数化したIDで検索する 190 | * res/values/public.xmlを検索すると見つかる 191 | 192 | 193 | ## 目的のレイアウトファイルを調べる その3 194 | 195 | * その2と途中まで同じ 196 | * aaptを使って調べる 197 | 198 | ```bash 199 | aapt d resources base.apk | grep 7f0a0020 200 | ``` 201 | 202 | ## 目的のレイアウトファイルを調べる その3 203 | 204 | * 画像を貼る 205 | 206 | 207 | ## apkを解体する 208 | 209 | * レイアウトファイルが見れるのでぱない 210 | * 難読化されてなければCustom Viewもわかる 211 | 212 | 213 | ## デザインの構造を解体する 214 | 215 | * 見たことないデザインの実装を依頼されたら**「このデザイン、どのアプリとかでありました?」**を聞く 216 | * mazikore daizi 217 | * そこから今まで紹介した解体術を使う 218 | 219 | 220 | ## まとめ 221 | 222 | * 解体してデザインの実装の参考にする 223 | * 気になったデザインを解体してみてね! 224 | * 解体こわくない! 225 | 226 | 227 | ## Thanks!! 228 | 229 | ---- 230 | 231 | ## おまけ 232 | 233 | 234 | ## adb shell dumpsys activity topで出るView Hierarchyの内容を理解する 235 | 236 | * コード読め案件 237 | * http://tools.oesf.biz/android-8.1.0_r1.0/xref/frameworks/base/core/java/android/view/View.java#5482 238 | 239 | ## adb shell settings put system font_scale周り 240 | 241 | * 定義は以下 242 | * http://tools.oesf.biz/android-8.1.0_r1.0/xref/frameworks/base/core/java/android/provider/Settings.java#2996 243 | 244 | ```java 245 | /** 246 | * Scaling factor for fonts, float. 247 | */ 248 | public static final String FONT_SCALE = "font_scale"; 249 | ``` 250 | 251 | * 0以上ならいくらでも値を設定できるので上限がない 252 | * いくらでも文字サイズ大きくできる 253 | * ヤバそうw 254 | * http://tools.oesf.biz/android-8.1.0_r1.0/xref/frameworks/base/core/java/android/provider/Settings.java#3001 255 | 256 | ```java 257 | private static final Validator FONT_SCALE_VALIDATOR = new Validator() { 258 | @Override 259 | public boolean validate(String value) { 260 | try { 261 | return Float.parseFloat(value) >= 0; 262 | } catch (NumberFormatException e) { 263 | return false; 264 | } 265 | } 266 | }; 267 | ``` 268 | 269 | 270 | ## adb shell wm density周り 271 | 272 | * http://tools.oesf.biz/android-8.1.0_r1.0/xref/frameworks/base/cmds/wm/src/com/android/commands/wm/Wm.java 273 | * adb shell wm実行した時に動くやーつ 274 | * adb shell wm density XXXで動くところ 275 | * http://tools.oesf.biz/android-8.1.0_r1.0/xref/frameworks/base/cmds/wm/src/com/android/commands/wm/Wm.java#198 276 | * 72以上なら設定できそう 277 | 278 | ```java 279 | private void runDisplayDensity() throws Exception { 280 | String densityStr = nextArg(); 281 | int density; 282 | if (densityStr == null) { 283 | try { 284 | int initialDensity = mWm.getInitialDisplayDensity(Display.DEFAULT_DISPLAY); 285 | int baseDensity = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY); 286 | System.out.println("Physical density: " + initialDensity); 287 | if (initialDensity != baseDensity) { 288 | System.out.println("Override density: " + baseDensity); 289 | } 290 | } catch (RemoteException e) { 291 | } 292 | return; 293 | } else if ("reset".equals(densityStr)) { 294 | density = -1; 295 | } else { 296 | try { 297 | density = Integer.parseInt(densityStr); 298 | } catch (NumberFormatException e) { 299 | System.err.println("Error: bad number " + e); 300 | return; 301 | } 302 | if (density < 72) { 303 | System.err.println("Error: density must be >= 72"); 304 | return; 305 | } 306 | } 307 | try { 308 | if (density > 0) { 309 | // TODO(multidisplay): For now Configuration only applies to main screen. 310 | mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density, 311 | UserHandle.USER_CURRENT); 312 | } else { 313 | mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, 314 | UserHandle.USER_CURRENT); 315 | } 316 | } catch (RemoteException e) { 317 | } 318 | } 319 | ``` -------------------------------------------------------------------------------- /Androidエンジニア_デザイン部_#1/images/dd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Androidエンジニア_デザイン部_#1/images/dd.png -------------------------------------------------------------------------------- /Androidエンジニア_デザイン部_#1/images/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Androidエンジニア_デザイン部_#1/images/font.png -------------------------------------------------------------------------------- /Androidエンジニア_デザイン部_#1/images/show_l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Androidエンジニア_デザイン部_#1/images/show_l.png -------------------------------------------------------------------------------- /Androidエンジニア_デザイン部_#1/images/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Androidエンジニア_デザイン部_#1/images/view.png -------------------------------------------------------------------------------- /DroidKaigi_ランチタイムLT会_Vol.1/README.md: -------------------------------------------------------------------------------- 1 | # App hibernation 2 | 3 | ## App hibernationとは? 4 | 5 | - Android 12から入った仕組み 6 | - 数ヶ月利用されていないアプリをシステムがhibernation stateにしますよーってやつ 7 | - Android 11で導入されたAuto-reset permissionsを進化させたやつ 8 | 9 | ## App hibernationとは? 10 | 11 | https://developer.android.com/topic/performance/app-hibernation 12 | 13 | 14 | ## Android11から導入されたAuto-reset permissionsを調べてみてわかったこと 15 | 16 | https://hack-it-iron.hatenablog.com/entry/2020/12/14/081217 17 | 18 | 19 | ## hibernationがアプリに与える影響 20 | 21 | 図はる 22 | 23 | 24 | ## Making permissions auto-reset available to billions more devices 25 | 26 | - https://android-developers.googleblog.com/2021/09/making-permissions-auto-reset-available.html 27 | 28 | 29 | ## システムがアプリを使用しているとみなすアクションはなにか? 30 | 31 | 図はる 32 | 33 | 34 | ## システムがアプリを使用しているとみなすアクションはなにか? 35 | 36 | - https://developer.android.com/topic/performance/app-hibernation#app-usage 37 | 38 | 39 | ## ドキュメントを読んで疑問に思ったこと 40 | 41 | - 数ヶ月利用されていないって具体的な数字は? 42 | - どのくらいの頻度でhibernationのチェックが行われるのか? 43 | - App usageってどうやってカウントしてるのか? 44 | - hibernation statusなアプリの実行制御をどうやってやってるのか? 45 | 46 | 47 | ## 数ヶ月利用されていないって具体的な数字は? 48 | 49 | - デフォルトでは90日間 = 約三ヶ月 50 | - 結構長いね! 51 | 52 | ```java 53 | private val DEFAULT_UNUSED_THRESHOLD_MS = TimeUnit.DAYS.toMillis(90) 54 | ``` 55 | 56 | 57 | ## 数ヶ月利用されていないって具体的な数字は? 58 | 59 | - 期間のしきい値を変更することはできる 60 | 61 | ```java 62 | // 未使用期間のしきい値を1分に変更 63 | adb shell device_config put permissions auto_revoke_unused_threshold_millis2 60000 64 | 65 | // 設定できているかを確認 66 | adb shell device_config get permissions auto_revoke_unused_threshold_millis2 67 | ``` 68 | 69 | 70 | ## どのくらいの頻度でhibernationのチェックが行われるのか? 71 | 72 | - デフォルトでは15日間隔 73 | - (あれ...?そんな高頻度じゃないのね...😂) 74 | 75 | ```java 76 | private val DEFAULT_CHECK_FREQUENCY_MS = TimeUnit.DAYS.toMillis(15) 77 | ``` 78 | 79 | ## どのくらいの頻度でhibernationのチェックが行われるのか? 80 | 81 | - こちらも頻度を変更することができる 82 | 83 | ```java 84 | // 実行周期を15分に変更 85 | adb shell device_config put permissions auto_revoke_check_frequency_millis 900000 86 | 87 | // 設定できているかを確認 88 | adb shell device_config get permissions auto_revoke_check_frequency_millis 89 | ``` 90 | 91 | 92 | ## App usageってどうやってカウントしてるのか? 93 | 94 | - UsageStatsManagerからのリスナーを受け取れる仕組みがあり、それでカウントしている 95 | - ちなみにアプリが利用されているイベントが飛んできたら、すぐにhibernationからの復帰が実行される 96 | 97 | ```java 98 | private final UsageEventListener mUsageEventListener = (userId, event) -> { 99 | if (!isAppHibernationEnabled()) { 100 | return; 101 | } 102 | final int eventType = event.mEventType; 103 | if (eventType == UsageEvents.Event.USER_INTERACTION 104 | || eventType == UsageEvents.Event.ACTIVITY_RESUMED 105 | || eventType == UsageEvents.Event.APP_COMPONENT_USED) { 106 | final String pkgName = event.mPackage; 107 | setHibernatingForUser(pkgName, userId, false); 108 | setHibernatingGlobally(pkgName, false); 109 | } 110 | }; 111 | ``` 112 | 113 | 114 | ## hibernation statusなアプリの実行制御をどうやってやってるのか? 115 | 116 | - わからなかった...🙏🏻 117 | 118 | 119 | ## その他 内部構造を調べてわかったこと 120 | 121 | - Android 12ではAncroid 11でのAuto-reset permissionsの実装がHibernationPolicyとかに変わってそう 122 | - AppHibernationServiceは管理する役割をやっている。HibernationControllerはPermissionなどの無効化などの処理をしている。管理と実行で役割が分かれているっぽい 123 | - adb shell dumpsys app_hibernationすればAppHibernationServiceをdumpできる 124 | - hibernationから復帰すると、ACTION_BOOT_COMPLETED とACTION_LOCKED_BOOT_COMPLETEDがbroadcastで発火する 125 | - hibernationの情報は以下みたいな場所に保存している 126 | - /data/system/hibernation/states 127 | - /data/system_ce/0/hibernation/states 128 | 129 | 130 | ## 参考コード 131 | 132 | - https://cs.android.com/android/platform/superproject/+/master:packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/hibernation/ 133 | - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/apphibernation/AppHibernationManager.java 134 | - https://cs.android.com/android/platform/superproject/+/master:packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationController.kt 135 | - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/apphibernation/ 136 | - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/apphibernation/AppHibernationService.java 137 | - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java 138 | - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/apphibernation/GlobalLevelState.java 139 | - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/apphibernation/UserLevelState.java 140 | - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java 141 | - https://cs.android.com/android/platform/superproject/+/master:packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt 142 | - https://cs.android.com/android/platform/superproject/+/master:packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt 143 | - https://cs.android.com/android/platform/superproject/+/master:packages/apps/Settings/src/com/android/settings/applications/HibernatedAppsPreferenceController.java 144 | - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/apphibernation/AppHibernationManager.java 145 | 146 | 147 | ## App hibernationの内部構造どう調べたか 148 | 149 | - DroidKaigi 2021 「できる!Android Framework Code Reading」 150 | - https://speakerdeck.com/operando/dekiru-android-framework-code-reading 151 | - https://www.youtube.com/watch?v=44ChiZXry1E&list=PLaOdaBFokChxuuWf0eXWaf5H35R1Aroaz 152 | - こちらをぜひ参考に🙏🏻 -------------------------------------------------------------------------------- /DroidKaigi_ランチタイムLT会_Vol.1/images/App_usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/DroidKaigi_ランチタイムLT会_Vol.1/images/App_usage.png -------------------------------------------------------------------------------- /DroidKaigi_ランチタイムLT会_Vol.1/images/Effects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/DroidKaigi_ランチタイムLT会_Vol.1/images/Effects.png -------------------------------------------------------------------------------- /Flutter_Meetup_Tokyo_1/README.md: -------------------------------------------------------------------------------- 1 | # Flutter Package & Plugin Package 2 | 3 | ## About Me 4 | 5 | ## 技術書典4で本出します! 6 | 7 | * こうして僕らは、書籍を売るアプリを作った 2.0.1 8 | * ぜひ買いに来てね! 9 | * Flutter全く関係ないです! 10 | * https://techbookfest.org/event/tbf04/circle/14710011 11 | 12 | 13 | ## これから紹介するドキュメントのURLだけ覚えて帰ってください!!それがすべてです!! 14 | 15 | 16 | ## Package & Plugin document 17 | 18 | * Using Packages 19 | * https://flutter.io/using-packages/ 20 | * Developing Packages & Plugins 21 | * https://flutter.io/developing-packages/ 22 | * Platform-specific code 23 | * https://flutter.io/platform-channels/ 24 | 25 | ## What is a Packages? 26 | 27 | * Dartはpubでパッケージ管理されてる 28 | * Flutterのパッケージを探すところもある 29 | * https://pub.dartlang.org/flutter 30 | * ライブラリと思ってもらうとわかりやすい 31 | 32 | 33 | ## Flutter Package types 34 | 35 | * FlutterではざっくりPackage typesが分かれてる 36 | * Dart packages 37 | * Plugin packages 38 | 39 | 40 | ## Dart packages 41 | 42 | * Dartで書かれたライブラリ 43 | * Flutter固有の機能が含まれているものもある 44 | 45 | ## Dart packages 46 | 47 | * fluro 48 | * The brightest, hippest, coolest router for Flutter. 49 | * Flutterの機能を使ってるけど、Nativeの機能は使ってない 50 | * https://pub.dartlang.org/packages/fluro 51 | 52 | ## Plugin packages 53 | 54 | * Dartで書かれたライブラリ 55 | * プラットフォーム(iOS/Android)固有の実装と組み合わせ 56 | * Native Bridgeライブラリ的な 57 | 58 | ## Plugin packages 59 | 60 | * shared_preferences 61 | * Wraps NSUserDefaults (on iOS) and SharedPreferences (on Android), providing a persistent store for simple data. 62 | * FlutterからNativeの機能・APIを呼び出す 63 | * https://pub.dartlang.org/packages/shared_preferences 64 | 65 | 66 | ## Flutter plugins 67 | 68 | * Flutter teamで管理されてるPlugin達 69 | * https://github.com/flutter/plugins 70 | * ここにあるのはPlugin packagesのみ 71 | * Native Bridge実装の参考になるコード満載っぽい 72 | * FirebaseのPluginが充実してる 73 | 74 | 75 | ## Native Bridgeの仕組み 76 | 77 | * このドキュメント読んでください! 78 | * Writing custom platform-specific code with platform channels 79 | * https://flutter.io/platform-channels/ 80 | 81 | ## Native Bridgeの仕組み 82 | 83 | ![](https://flutter.io/images/PlatformChannels.png) 84 | 85 | ## Developing Plugin Packages 86 | 87 | * 複雑なものじゃなけれなさくっと作れる 88 | * 各プラットフォームのAPI知ってると楽勝 89 | * pubへの公開も簡単 90 | 91 | 92 | ## Developing Plugin Packages 93 | 94 | * 今日の深夜に作った 95 | * Flutterから各プラットフォームの広告IDを取得するやーつー 96 | * https://pub.dartlang.org/packages/advertising_id 97 | * https://github.com/operando/advertising_id 98 | 99 | ## Create the plugin packages 100 | 101 | * IntelliJ or Android Studioから作るのが楽 102 | 103 | ![](./flutter_plugin.png) 104 | 105 | ## Create the plugin packages 106 | 107 | * コマンドからでも作れる 108 | * NativeのコードをSwiftとKotlinで書くなら以下 109 | * `flutter create --template=plugin -i swift -a kotlin advertising_id` 110 | 111 | ## [advertising_id.dart](https://github.com/operando/advertising_id/blob/master/lib/advertising_id.dart) 112 | 113 | ```dart 114 | import 'dart:async'; 115 | 116 | import 'package:flutter/services.dart'; 117 | 118 | class AdvertisingId { 119 | static const MethodChannel _channel = 120 | const MethodChannel('advertising_id'); 121 | 122 | static Future get id async { 123 | final String id = await _channel.invokeMethod('getAdvertisingId'); 124 | return id; 125 | } 126 | } 127 | ``` 128 | 129 | ## [AdvertisingIdPlugin.kt](https://github.com/operando/advertising_id/blob/master/android/src/main/kotlin/com/os/operando/advertisingid/AdvertisingIdPlugin.kt) 130 | 131 | ```kotlin 132 | class AdvertisingIdPlugin(private val registrar: Registrar) : MethodCallHandler { 133 | 134 | companion object { 135 | @JvmStatic 136 | fun registerWith(registrar: Registrar) { 137 | val channel = MethodChannel(registrar.messenger(), "advertising_id") 138 | channel.setMethodCallHandler(AdvertisingIdPlugin(registrar)) 139 | } 140 | } 141 | 142 | override fun onMethodCall(call: MethodCall, result: Result) { 143 | when (call.method) { 144 | "getAdvertisingId" -> thread { 145 | try { 146 | result.success(AdvertisingIdClient.getAdvertisingIdInfo(registrar.context()).id) 147 | } catch (e: Exception) { 148 | result.success("") 149 | } 150 | } 151 | else -> result.notImplemented() 152 | } 153 | } 154 | } 155 | ``` 156 | 157 | ## [SwiftAdvertisingIdPlugin.swift](https://github.com/operando/advertising_id/blob/master/ios/Classes/SwiftAdvertisingIdPlugin.swift) 158 | 159 | ```swift 160 | import Flutter 161 | import UIKit 162 | import AdSupport 163 | 164 | public class SwiftAdvertisingIdPlugin: NSObject, FlutterPlugin { 165 | public static func register(with registrar: FlutterPluginRegistrar) { 166 | let channel = FlutterMethodChannel(name: "advertising_id", binaryMessenger: registrar.messenger()) 167 | let instance = SwiftAdvertisingIdPlugin() 168 | registrar.addMethodCallDelegate(instance, channel: channel) 169 | } 170 | 171 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 172 | switch call.method { 173 | case "getAdvertisingId": 174 | var idfaString: String! 175 | let manager = ASIdentifierManager.shared() 176 | if manager.isAdvertisingTrackingEnabled { 177 | idfaString = manager.advertisingIdentifier.uuidString 178 | } else { 179 | idfaString = "" 180 | } 181 | result(idfaString) 182 | default: 183 | result(nil) 184 | } 185 | } 186 | } 187 | ``` 188 | 189 | ## [pubspec.yaml](https://github.com/operando/advertising_id/blob/master/pubspec.yaml) 190 | 191 | ```yaml 192 | name: advertising_id 193 | description: A Flutter plugin to access advertising ID. 194 | version: 0.9.0 195 | author: Shinobu Okano 196 | homepage: https://github.com/operando/advertising_id 197 | 198 | flutter: 199 | plugin: 200 | androidPackage: com.os.operando.advertisingid 201 | pluginClass: AdvertisingIdPlugin 202 | 203 | dependencies: 204 | flutter: 205 | sdk: flutter 206 | 207 | environment: 208 | sdk: ">=1.21.0 <3.0.0" 209 | flutter: ">=0.1.4" 210 | ``` 211 | 212 | ## Publishing packages 213 | 214 | * Publishのコマンドが用意されてる 215 | * --dry-runをつけて問題ないか確認 216 | * `flutter packages pub publish --dry-run` 217 | 218 | ## Publishing packages 219 | 220 | * ダメなところとか親切に教えてくれるので最高☺ 221 | 222 | ![](./pub.png) 223 | 224 | ## Publishing packages 225 | 226 | * pubspec.yamlの書き方はPubspec Formatのdocumentを見ると親切に書いてある 227 | * https://www.dartlang.org/tools/pub/pubspec 228 | 229 | ## Publishing packages 230 | 231 | * pubにpublishする 232 | * はじめてpubにpublishする時だけGoogleの認証が走る 233 | * `flutter packages pub publish` 234 | 235 | 236 | ## 疑問 237 | 238 | * pubにあげたpackageって消せないのかな?🤔 239 | 240 | 241 | ## まとめ 242 | 243 | * パッケージ管理はpubがちゃんとしてるので簡単! 244 | * Plugin Packageは簡単に作れる・公開できる 245 | * 各プラットフォームのAPI知ってると楽勝 246 | * **じゃんじゃんPlugin Package作るチャンス!** 247 | 248 | ## Thanks!! -------------------------------------------------------------------------------- /Flutter_Meetup_Tokyo_1/flutter_plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Flutter_Meetup_Tokyo_1/flutter_plugin.png -------------------------------------------------------------------------------- /Flutter_Meetup_Tokyo_1/pub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Flutter_Meetup_Tokyo_1/pub.png -------------------------------------------------------------------------------- /Flutter_Meetup_Tokyo_2/README.md: -------------------------------------------------------------------------------- 1 | # FlutterでQRコードリーダー的なアプリを雑に作ってみた 2 | 3 | ## スライド 4 | 5 | * https://speakerdeck.com/operando/flutterde-qrkodorida-woza-nizuo-tutemita 6 | 7 | ## Demo 8 | 9 | 10 | ## アプリのコード 11 | 12 | * Flutter QRCode Scanner APP 13 | * https://github.com/operando/FlutterQRScanner-App 14 | 15 | 16 | ## 作業時間 17 | 18 | * 5時間くらい 19 | 20 | ## 作る過程をざっくり紹介 21 | 22 | 23 | ## なぜQRコードリーダーアプリを作るのか 24 | 25 | * Androidの標準カメラアプリはQRコード読み込みできない 26 | * iOSはできる 27 | * 世にあるQRコードリーダーアプリ広告が出て嫌ー 28 | * 自分で作ればいいのでは? 29 | * Flutterでやるかー 30 | 31 | 32 | ## QRコードリーダーのLibraryを探す 33 | 34 | * QR Code Scanner Appを作ってるYouTubeを見つけた 35 | * Flutter: QR Code Scanner App | Barcode Scan 36 | * https://www.youtube.com/watch?v=siuJhQ9BqsU 37 | * Flutter QRCode Scanner APP 38 | * https://github.com/iampawan/FlutterQRScanner-App 39 | 40 | ## QRコードリーダーのLibraryを探す 41 | 42 | * この方のYouTubeチャンネルFlutter動画結構あって良さそう 43 | * MTechViral 44 | * https://www.youtube.com/channel/UCFTM1FGjZSkoSPDZgtbp7hA 45 | 46 | ## QR Code Scanner Appを動かしてみる 47 | 48 | * git cloneして、IntelliJ IDEAで開く 49 | * Androidアプリでビルドする 50 | 51 | ## 動いた 🍣 52 | 53 | 54 | ## QR Code Scanner Appのコードを見てみる 55 | 56 | * QRコード読み込みにはLibraryを使ってみるみたい 57 | * barcode_scan 58 | * https://github.com/apptreesoftware/flutter_barcode_reader 59 | 60 | 61 | ## QR Code Scanner Appのコードを見てみる 62 | 63 | * barcode_scanはQRコード読み込みにzxingを使ってる 64 | * https://github.com/zxing/zxing 65 | * GoogleのMobile Visionに差し替えたい欲が出てきた 66 | 67 | 68 | ## Flutter Mobile Vision Packageを探してみる 69 | 70 | * あったー! 71 | * flutter_mobile_vision 72 | * https://github.com/edufolly/flutter_mobile_vision 73 | * ただiOSは未対応っぽい 74 | 75 | 76 | ## flutter_mobile_visionに差し替える 77 | 78 | * 簡単に差し替えられた 79 | 80 | ```dart 81 | Future _scanQR() async { 82 | List barcodes = []; 83 | try { 84 | barcodes = await FlutterMobileVision.scan( 85 | flash: false, 86 | autoFocus: true, 87 | formats: Barcode.ALL_FORMATS, 88 | multiple: false, 89 | showText: true, 90 | camera: FlutterMobileVision.CAMERA_BACK, 91 | fps: 30.0, 92 | ); 93 | setState(() { 94 | result = barcodes[0].displayValue; 95 | }); 96 | } on Exception { 97 | barcodes.add(new Barcode('Failed to get barcode.')); 98 | } 99 | } 100 | 101 | @override 102 | Widget build(BuildContext context) { 103 | ... 104 | body: Center( 105 | ... 106 | floatingActionButton: FloatingActionButton.extended( 107 | icon: Icon(Icons.camera_alt), 108 | label: Text("Scan"), 109 | onPressed: _scanQR, 110 | ), 111 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, 112 | ); 113 | } 114 | ``` 115 | 116 | ## なんだ、できちまったぜ... 🍣 117 | 118 | 119 | ## 機能追加してみよう 120 | 121 | * 読み込んだQRコードの文字列をシェアする 122 | * 読み込み履歴を作る 123 | * 今回はこっちの話をします 124 | 125 | 126 | ## 読み込み履歴を作る 127 | 128 | * 読み込み履歴画面を作る 129 | * 読み込み履歴画面への遷移を作る 130 | * 読み込んだ情報をDBに保存する 131 | * 読み込み履歴一覧を表示する 132 | 133 | 134 | ## 読み込み履歴画面を作る 135 | 136 | * HistoryStateの中身は後ほど 137 | 138 | ```dart 139 | class History extends StatefulWidget { 140 | @override 141 | HistoryState createState() { 142 | return HistoryState(); 143 | } 144 | } 145 | ``` 146 | 147 | ## 読み込み履歴画面への遷移を作る 148 | 149 | ``` 150 | void main() => runApp(MaterialApp( 151 | debugShowCheckedModeBanner: false, 152 | home: HomePage(), 153 | routes: {'history': (_) => History()}, 154 | )); 155 | ``` 156 | 157 | ## 読み込み履歴画面にListViewを表示する 158 | 159 | * ListViewの使い方を公式ドキュメントから学ぶ 160 | * とりあえず固定データを表示してみる 161 | 162 | ## 読み込み履歴画面にListViewを表示する 163 | 164 | ```dart 165 | class HistoryState extends State { 166 | @override 167 | Widget build(BuildContext context) { 168 | return Scaffold( 169 | appBar: AppBar( 170 | title: Text("Scanner History"), 171 | ), 172 | body: new ListView.builder( 173 | itemCount: 1, 174 | itemBuilder: (context, index) { 175 | return ListTile(title: Text("ニート")); 176 | })); 177 | } 178 | } 179 | ``` 180 | 181 | ## 読み込んだ情報をDBに保存する 182 | 183 | * DB Library探してみる 184 | * sqflite 185 | * https://github.com/tekartik/sqflite 186 | 187 | 188 | ## sqfliteの使い方を学ぶ 189 | 190 | * README読んだり、example読んだりする 191 | * あとは雰囲気でコピペしてきた、書き換える 192 | * exampleがちょっとわかりにくかったので頑張る... 193 | 194 | 195 | ## DBに保存された情報見たい... 196 | 197 | * AndroidならStetho使えば!! 198 | * flutter_stetho 199 | * https://github.com/brianegan/flutter_stetho 200 | * でもDB見れなかった... 201 | * sqfliteでDBを作ってるディレクトリがちょっとあれかも 202 | 203 | 204 | ## 保存した読み込み履歴をListViewに表示する 205 | 206 | * DBから履歴を読み込んで、取得できたらsetStateするだけ 207 | 208 | 209 | ## 保存した読み込み履歴をListViewに表示する 210 | 211 | ```dart 212 | class HistoryState extends State { 213 | List _items = []; 214 | 215 | @override 216 | void initState() { 217 | super.initState(); 218 | _initDatabase(); 219 | } 220 | 221 | _initDatabase() async { 222 | String path = await getDatabaseFilePath("scan_history.db"); 223 | Database db = await openReadOnlyDatabase(path); 224 | 225 | List data = await db.query("scan_hisoty", columns: ["text"]); 226 | 227 | List items = []; 228 | data.forEach((e) => items.add(ScanItem.fromMap(e))); 229 | 230 | setState(() { 231 | _items = items; 232 | }); 233 | 234 | await db.close(); 235 | } 236 | 237 | @override 238 | Widget build(BuildContext context) { 239 | return Scaffold( 240 | ... 241 | body: new ListView.builder( 242 | itemCount: _items.length, 243 | itemBuilder: (context, index) { 244 | return ListTile(title: Text("${_items[index].text}")); 245 | })); 246 | } 247 | } 248 | ``` 249 | 250 | ## アプリの最終的なDependencies 251 | 252 | ```yaml 253 | dependencies: 254 | flutter: 255 | sdk: flutter 256 | 257 | cupertino_icons: ^0.1.2 258 | flutter_mobile_vision: ^0.1.0 259 | share: "^0.5.0" 260 | sqflite: "^0.8.9" 261 | path_provider: "^0.4.0" 262 | 263 | dev_dependencies: 264 | flutter_stetho: 0.1.1 265 | flutter_test: 266 | sdk: flutter 267 | ``` 268 | 269 | 270 | ## 作ってみて感じたこと 🍣 271 | 272 | * とりあえずLibrary探しがち 273 | * 自分が実装しなくてもきっとある感 274 | * 実際に大体はある 275 | * 片方のプラットフォームだけ実装しても全然良さそう 276 | * 作りたいものをすぐ作れる 277 | * よく知らないから細かいことにこだわらなくなる 278 | 279 | ## 作ってみて感じたこと 🍣 280 | 281 | * async / await雑に使いがち 282 | * 理解してこうな! 283 | * Text表示する方法忘れがち 284 | * コンポーネントに文字列指定するプロパティがあると勘違いする 285 | * 基本Widgetだよ! 286 | 287 | ## 作ってみて感じたこと 🍣 288 | 289 | * 最悪main.dartに全部書いても良さそう 290 | * あとで分ければいいし 291 | * コピペしすぎるとハマりがち 292 | * コピペしたコードが予期せぬ動きをしてるのあるよね 293 | * プログラミングの懐かしさを感じた 294 | 295 | ## 作ってみて感じたこと 🍣 296 | 297 | * SDKの使い方わからなかったらドキュメント読むか中のコード読む方が早そう 298 | * ORM Libraryがほしいところ... 299 | * Dartで実装できるかな? 300 | 301 | ## 作ってみて感じたこと 🍣 302 | 303 | * droidkaigi2018-flutter見てみると良さそう 304 | * https://github.com/konifar/droidkaigi2018-flutter 305 | 306 | ## Thanks! -------------------------------------------------------------------------------- /Gunosy_beer/README.md: -------------------------------------------------------------------------------- 1 | # 5分で資料作ってSlideShareにアップロードする錬金術 2 | 3 | # A 4 | 5 | * エムスリー x Gunosy Beer bash! 6 | 7 | ![](./images/app.png) 8 | 9 | # メルカリ、2015年ベストアプリに選ばれました!! 10 | 11 | ![](./images/mercari.png) 12 | 13 | # ありがとうございます! 14 | 15 | 16 | # ゆるびぃ会の宣伝 17 | 18 | * いつもエムスリーさん、お世話になってます!! 19 | * 森さん、ありがとうございます! 20 | * http://yuruby.connpass.com/ 21 | 22 | # ゆるびぃ会ってなんですか?? 23 | 24 | # 女子会みたいなものです 25 | 26 | # ※女子がいるとは言ってない 27 | 28 | # 本題 29 | 30 | # 用意するもの 31 | 32 | * Terminal 33 | * お好きなエディター 34 | * Keynote 35 | * ブラウザ 36 | 37 | # まずはMarkdownで発表内容書き出す 38 | 39 | * 好きなように書けや!!! 40 | 41 | # githubにpushする 42 | 43 | * https://github.com/operando/Notes 44 | * SlideShareの書き出しがショボいから 45 | * 文字起こししておけば、後で見る人楽 46 | 47 | # md2keyでMarkdownからKeynoteを錬金する 48 | 49 | * md2key 50 | * Convert markdown to keynote 51 | * https://github.com/k0kubun/md2key 52 | 53 | # md2key Installしよう!! 54 | 55 | ```ruby 56 | gem install md2key 57 | ``` 58 | 59 | # md2keyのいいところ 60 | 61 | * AZUSA Colorsとめっちゃ相性いい!! 62 | * formatがちゃんと決まってるから! 63 | * gemなのでInstall簡単!! 64 | 65 | # さて、錬金するぞ!! 66 | 67 | # md2key README.md 68 | 69 | # あら不思議!!資料ができちゃった!! 70 | 71 | # 素晴らしい!! 72 | 73 | # SlideShareにあげるぞ!! 74 | 75 | # 日本語タイトルはサムネがうまく生成されないから気をつけろ!! 76 | 77 | * SlideShareさん、まじぱねーっす 78 | * どうすんだー!! 79 | * 一枚目のスライドを画像にしてしまえ!! 80 | 81 | # DroidKaigiやります!! 82 | 83 | * DroidKaigi 2016 84 | * みんな来てね!! 85 | * https://droidkaigi.github.io/2016/ 86 | * http://droidkaigi.connpass.com/event/23512/ 87 | 88 | ![](./images/image.png) 89 | 90 | 91 | # Thanks!! 92 | 93 | 94 | -------------------------------------------------------------------------------- /Gunosy_beer/images/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Gunosy_beer/images/app.png -------------------------------------------------------------------------------- /Gunosy_beer/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Gunosy_beer/images/image.png -------------------------------------------------------------------------------- /Gunosy_beer/images/mercari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Gunosy_beer/images/mercari.png -------------------------------------------------------------------------------- /Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/README.md: -------------------------------------------------------------------------------- 1 | # Support Library 28.0.0 Alpha 1に触れてみる 2 | 3 | ## スライド 4 | 5 | https://speakerdeck.com/operando/support-library-28-dot-0-0-alpha-1nihong-retemiru 6 | 7 | 8 | ## Support Library 28.0.0 Alpha 1 9 | 10 | * https://developer.android.com/topic/libraries/support-library/revisions.html#28-0-0-alpha1 11 | 12 | 13 | ## Support Library 28.0.0 Alpha 1 14 | 15 | * バグもあるし、API surface変わるかもなので! 16 | * 何が起きてもびっくりしない!くらいの気持ちで試すw 17 | 18 | 19 | ## Important changes 20 | 21 | 22 | ## androidx: Hello World! 23 | 24 | * package nameがandroidxになる 25 | * Android KTXから採用され始めたやつ 26 | * 新しいSupport Libraryからなる 27 | * heifwriter,recyclerview-selection 28 | 29 | 30 | ## Split libraries 31 | 32 | * split parts of support-core-ui, support-core-utils, and support-compat into smaller libraries 33 | 34 | 35 | ## Split libraries 36 | 37 | * 依存関係を切り離すために小さいLibraryに分割する 38 | * Google's Maven Repositoryを見るとどの単位でLibraryがあるのかわかる 39 | * https://dl.google.com/dl/android/maven2/index.html 40 | 41 | 42 | ## Split libraries 43 | 44 | ```gradle 45 | implementation "com.android.support:asynclayoutinflater:28.0.0-alpha1" 46 | implementation "com.android.support:drawerlayout:28.0.0-alpha1" 47 | implementation "com.android.support:viewpager:28.0.0-alpha1" 48 | ``` 49 | 50 | 51 | ## New APIs 52 | 53 | 54 | ## recyclerview-selection 55 | 56 | * 詳しく書いてくれたkgmyshinさんの見て! 57 | * Support Library 28.0.0 alpha新APIのrecyclerview-selectionを使ってみた 58 | * https://inside.dmm.com/entry/2018/03/22/recyclerview-selection 59 | 60 | 61 | ## HeifWriter 62 | 63 | * High Efficiency Image File Format 64 | * iOSはiOS11から採用してる 65 | * Android Pでも公式サポート 66 | * HeifWriterはHEIF-formatで書き込みができる 67 | * ReadもSupport Libraryで出ること期待したい! 68 | 69 | 70 | ## HeifWriter 71 | 72 | * https://developer.android.com/reference/androidx/heifwriter/HeifWriter.html 73 | 74 | 75 | ## New application theme 76 | 77 | * `Theme.MaterialComponents` 78 | 79 | 80 | ## Theme.MaterialComponents 81 | 82 | ```xml 83 | 88 | ``` 89 | 90 | 91 | ## Theme.MaterialComponents 92 | 93 | * Theme.MaterialComponentsの定義 94 | * https://github.com/material-components/material-components-android/blob/master/lib/java/android/support/design/theme/res/values/themes.xml#L28 95 | * Base.V14.Theme.MaterialComponentsの定義 96 | * https://github.com/material-components/material-components-android/blob/master/lib/java/android/support/design/theme/res/values/themes_base.xml#L33 97 | 98 | 99 | ## New components 100 | 101 | * BottomAppBar 102 | * Chip 103 | * ChipGroup 104 | * MaterialButton 105 | * MaterialCardView 106 | 107 | 108 | ## New components 109 | 110 | * コードはMaterial Components for Androidを参照すると良さそう 111 | * https://github.com/material-components/material-components-android 112 | 113 | 114 | ## MaterialButton 115 | 116 | * rippleColorとかstrokeの設定ができる 117 | * selectorとか書かなくて良くなりそうなので素晴らしい! 118 | * 4系でrippleColorで背景色が塗りつぶされるbugっぽいのがある 119 | 120 | 121 | ## MaterialButton 122 | 123 | ```xml 124 | 133 | ``` 134 | 135 | ![](./mb.png) 136 | 137 | 138 | ## MaterialButton 139 | 140 | ```xml 141 | 152 | ``` 153 | 154 | ![](./mb2.png) 155 | 156 | 157 | ## New components 158 | 159 | * 紹介しなかったComponentや使い方は以下を読むと書いてあります! 160 | * Exploring the v28 Android Design Support Library Additions 161 | * https://medium.com/google-developer-experts/exploring-the-v28-android-design-support-library-2c96c6031ae8 162 | 163 | ## Slices 164 | 165 | ## What are Slices? 166 | 167 | * Slices provides a framework for apps to embed templated content from other apps. 168 | 169 | 170 | ## What are Slices? 171 | 172 | * とある解説ブログでGoogle Assistantとかに自身のアプリの情報をPlugin的に提供できるようにするAPI
という仮説が書かれてる 173 | * Pluginを提供するのに価値があるアプリは試して
みるといいかも 174 | * Pluginを活用して面白いアプリを作れるかも 175 | 176 | 177 | ## What are Slices? 178 | 179 | * まだ謎に包まれてるAPI 180 | * ただすごい興味深い 181 | * Android P Preview 2に期待! 182 | * まだPreview 1なのでAPIはバギー 183 | 184 | 185 | ## What are Slices? 186 | 187 | * 他人のアプリが提供するSliceを自身のアプリに
表示することで、他人のアプリのUIや機能が
自身のアプリで使える感 188 | * その逆もできる = 自身のアプリがSliceを提供する 189 | * UIはある程度決まった形 190 | * Slice Provide AppとSlice Host App 191 | 192 | 193 | ## Slice Provide App 194 | 195 | * SliceProviderを実装する 196 | * SliceProviderはContentProviderを継承したもの 197 | * Format BuilderみたいなのでUI(Slice)を作る 198 | * SliceProviderがUri or Intentに応じたSliceを返す 199 | 200 | 201 | ## Slice Host App 202 | 203 | * SliceManagerにUri or Intentを渡しSliceProviderとbindする 204 | * SliceProviderから返ってきたSliceをSliceViewにセットする 205 | 206 | 207 | ## Slicesの大まなか流れ 208 | 209 | ![](./slice.png) 210 | 211 | 212 | ## Slices & Permission 213 | 214 | * SliceProviderからSliceを取得するにはPermissionが必要 215 | * Permissionに関するAPI周りがまだ謎いし、バギー 216 | * こんな感じっぽい!の理解でOK。変わるかもしれないし 217 | 218 | 219 | ## Slices & Permission 220 | 221 | * Permissionさえちゃんとユーザが承認すれば
どのアプリでもSliceProviderを提供してる
アプリからSliceを取得できる 222 | * Slice Host Appが単一アプリ or 全てのアプリのSliceを取得できるようにするかどうか 223 | 224 | ## Slices & Permission 225 | 226 | ![](./permission.png) 227 | 228 | 229 | ## Slices Support Library 230 | 231 | * `com.android.support:slices-builders` 232 | * Slice Provide AppのためのAPI 233 | * `com.android.support:slices-view` 234 | * Slice Host AppのためのAPI 235 | * `com.android.support:slices-core` 236 | * Slices APIのコア 237 | 238 | 239 | ## Slice Provide Appの実装 240 | 241 | 242 | ## SliceProviderの実装 243 | 244 | * onBindSliceでUriに応じたSliceを返す 245 | * SliceはBuilderを使って作る 246 | * ListBuilder, GridBuilderなどがある 247 | * ある程度決まったUIのフォーマットで表現する 248 | 249 | ## SliceProviderの実装 250 | 251 | ```kotlin 252 | class SampleSliceProvider : SliceProvider() { 253 | 254 | private var counter = 0 255 | 256 | override fun onCreateSliceProvider(): Boolean { 257 | return true 258 | } 259 | 260 | override fun onBindSlice(sliceUri: Uri): Slice { 261 | return when (sliceUri.path) { 262 | "/time" -> createTimeSlice(sliceUri) 263 | else -> createTimeSlice(sliceUri) 264 | } 265 | } 266 | 267 | private fun createTimeSlice(sliceUri: Uri): Slice = ListBuilder(context, sliceUri) 268 | .apply { 269 | counter++ 270 | setHeader( 271 | ListBuilder.HeaderBuilder(this) 272 | .setTitle("What's the time now?") 273 | ) 274 | addRow( 275 | ListBuilder.RowBuilder(this) 276 | .setTitle("It is ${SimpleDateFormat("HH:mm").format(Calendar.getInstance().time)}") 277 | ) 278 | addRow( 279 | ListBuilder.RowBuilder(this) 280 | .setTitle("Slice has called $counter times") 281 | ) 282 | } 283 | .build() 284 | } 285 | ``` 286 | 287 | 288 | ## SliceProviderをAndroidManifestに定義 289 | 290 | ```xml 291 | 292 | 293 | 294 | 296 | 297 | 301 | 302 | 303 | ``` 304 | 305 | ## SliceProviderをAndroidManifestに定義 306 | 307 | * exported="true"してないと、SliceManagerでbindする時に落ちるのでつけてる 308 | * 公開したらPermissionとか関係ないのでは?って気持ち 309 | * ドキュメンドがまだ曖昧なのでbugかも? 310 | 311 | 312 | ## Slice Provide Appの実装 313 | 314 | ## レイアウトにSliceViewを追加 315 | 316 | * Sliceを表示するView 317 | * https://developer.android.com/reference/androidx/slice/widget/SliceView.html 318 | 319 | 320 | ## レイアウトにSliceViewを追加 321 | 322 | ```xml 323 | 327 | ``` 328 | 329 | ## Permissionのチェック + 認可 330 | 331 | * ここは長いのと、bugっぽいのがあるため割愛 332 | * 今後API変わりそうな雰囲気 333 | 334 | 335 | ## Permissionのチェック + 認可 336 | 337 | * Slice Provide AppのSliceProviderにアクセスできるようにするために、内部実装ではContextWrapper#grantUriPermissionメソッドを使って、別パッケージでもアクセスできるように
してるっぽい? 338 | 339 | 340 | ## Sliceの表示 341 | 342 | * SliceManagerを使用してUriを使ってSliceProviderをbindする 343 | * SliceProviderから返ってきたSliceをSliceViewにセットする 344 | 345 | 346 | ## Sliceの表示 347 | 348 | ```kotlin 349 | val slice = sliceManager.bindSlice(sliceUri) 350 | sliceView.setSlice(slice) 351 | ``` 352 | 353 | 354 | ## Android P Slice 355 | 356 | * Android PではSliceManagerServiceが存在する 357 | * つまり、System Serviceの一種 358 | 359 | 360 | ## Sliceユースケース 361 | 362 | * 商品検索結果をSliceで返す 363 | * メルカリ 364 | * Slice Provide App側 365 | * 機能をPlguinとして提供するイメージ 366 | 367 | 368 | ## Sliceユースケース 369 | 370 | * 発言などをトリガーにSliceを表示する 371 | * LINE、Google Assistant 372 | * メッセージング、アシスト 373 | * Slice Host App側 374 | 375 | 376 | ## Android P Slice 377 | 378 | * Android PではSliceManagerServiceが存在する 379 | * つまり、System Serviceの一種 380 | 381 | 382 | ## Sliceの謎 383 | 384 | * SliceProviderを提供するアプリの把握 385 | * SliceProviderが反応するUriのFormatの把握 386 | * どんなアプリがどんなSliceを提供してるのか
知る方法がない気がする 387 | 388 | 389 | ## Sliceをさらに深く知る 390 | 391 | * Android P Slices: the missing documentation — part 1 and 2 392 | * https://blog.novoda.com/android-p-slices-missing-documentation-part-1/ 393 | * https://blog.novoda.com/android-p-slices-missing-documentation-part-2/ 394 | 395 | 396 | ## Sliceをさらに深く知る 397 | 398 | * Sample App 399 | * https://github.com/novoda/spikes/tree/master/sliceanddice 400 | * https://github.com/operando/Android_Support_Library_Sample 401 | 402 | 403 | ## Support Library 28.0.0 Alpha 1まとめ 404 | 405 | * 着実にいいAPIは増えてる 406 | * Android P Preview 2が出たらまたガラッと変わりそう 407 | * 深く調べると新しい何かが見えてくる!かも... 408 | 409 | 410 | ## Thanks!! 411 | -------------------------------------------------------------------------------- /Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/mb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/mb.png -------------------------------------------------------------------------------- /Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/mb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/mb2.png -------------------------------------------------------------------------------- /Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/permission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/permission.png -------------------------------------------------------------------------------- /Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/slice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Mercari_Meetup_for_Mobile_App_Engineer_in_Fukuoka/slice.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Note -------------------------------------------------------------------------------- /Roppongi.aar_2/README.md: -------------------------------------------------------------------------------- 1 | # [Roppongi.aar #2](http://roppongi-aar.connpass.com/event/21907/) 2 | 3 | # Title 4 | 5 | 考え中ー 6 | 7 | ## 候補 8 | 9 | * Android & Chrome 10 | * Android M Permissions 11 | * JobScheduler 12 | + オレオレ Android Development Kit 13 | * Permission Controller Tools 14 | -------------------------------------------------------------------------------- /Shibuya.apk2/README.md: -------------------------------------------------------------------------------- 1 | # Screenshots Test Spoon + Espresso(shibuya.apk #2) 2 | 3 | ## Spoon 4 | 5 | https://github.com/square/spoon 6 | 7 | ## Espresso 8 | 9 | https://code.google.com/p/android-test-kit/wiki/Espresso 10 | 11 | ## Spoon Gradle Plugin 12 | 13 | https://github.com/stanfy/spoon-gradle-plugin 14 | 15 | ## Demo 16 | 17 | https://github.com/operando/EspressoSpoonSample 18 | 19 | ## 俺が考えた最強のBest Practice 20 | 21 | ### 画面表示ができればOK 22 | 23 | 画面表示までに全力を注ぐ 24 | 25 | Espressoで細かい操作はしない 26 | 27 | 28 | ### Espressoを最小限に使う 29 | 30 | あくまで最小限 31 | 32 | 最大限使わない 33 | 34 | 頑張らない 35 | 36 | 37 | ### createIntentパターンを使う 38 | 39 | Activity起動に必要な情報がわかりやすい 40 | 41 | 表示したい画面のIntentが大事 42 | 43 | 44 | ```java 45 | public class LoginSuccessActivity extends AppCompatActivity { 46 | 47 | private static final String EMAIL = "email"; 48 | 49 | public static Intent createIntent(Context context, String email) { 50 | Intent i = new Intent(context, LoginSuccessActivity.class); 51 | i.putExtra(EMAIL, email); 52 | return i; 53 | } 54 | } 55 | ``` 56 | 57 | 58 | ### 実機とエミュレータを使い分ける 59 | 60 | 実機は機種依存が分かる 61 | 62 | エミュレータは解像度が柔軟に変更できる 63 | 64 | 65 | ### 大雑把に確認する 66 | 67 | 厳密に結果を確認しない 68 | 69 | 表示するデータのこがわらない 70 | 71 | 72 | ### 全画面撮ろうとしない 73 | 74 | アプリの規模によっては全画面無理 75 | 76 | 全画面撮れても価値があるのか疑問 77 | 78 | 撮って価値ある画面に着目する 79 | 80 | 81 | ### 前提条件が厳しい画面は潔く諦める 82 | 83 | とにかく頑張らない 84 | 85 | 86 | ### とにかく頑張らない 87 | 88 | 気軽に楽しくがモットー 89 | 90 | ハマるな危険 = 頑張り過ぎちゃう 91 | -------------------------------------------------------------------------------- /Shibuya.apk51/README.md: -------------------------------------------------------------------------------- 1 | # private space 2 | 3 | ## 自己紹介 4 | 5 | - 岡野 忍(@operandoOS) 6 | - 株式会社LinQ / EM & Android Engineer 7 | - 位置情報共有アプリ whooを作ってます🍩 8 | - ポケモンGOでポケモンマスター目指してます💪 9 | 10 | ## whooの紹介 11 | 12 | - 家族や友人同士がリアルタイムで位置情報を共有できるアプリ 13 | - コミュニケーションを楽しむ機能も充実しています 14 | - ほとんどの画面がDialogFragmentで実装されているちょっと変わった作り 15 | 16 | ## private space 17 | 18 | - Android 15で実装された機能 19 | - 追加の認証が必要な独立した空間をデバイス上に作成し、そこに
プライベートなアプリを配置することでセキュリティを確保してる 20 | - private space用の新しいユーザーと非公開プロファイルが作成され
そこアプリやデータが保存される 21 | - private spaceの存在を隠すことができる 22 | - メインプロファイルとprivate spaceをシームレスに切り替えられる 23 | 24 | ## システムユーザーとprivate spaceの関係性 25 | 26 | ![](./images/image.png) 27 | 28 | 29 | ## システムユーザーとprivate spaceの関係性 30 | 31 | - ぞれぞれは独立しているので、データの移動などはできない 32 | - 一部設定はシステムユーザーのものが反映される(例えば位置情報ON/OFFとか) 33 | - ただprivate spaceから設定値を変えることはできなさそう(例えば位置情報ON/OFFとか) 34 | - 位置情報に関してはprivate spaceでの利用を制限できる設定がある 35 | 36 | ## **システムユーザーと**private spaceの関係性 37 | 38 | - システム ユーザーでしかprivate spaceは作成できない 39 | - システム ユーザーからprivate spaceのデータ(写真などのメディア)を参照する方法はある 40 | - システム ユーザーからprivate spaceのアプリにデータを共有する方法はある 41 | - その逆(private spaceからシステム ユーザー)はできない 42 | 43 | ## システム ユーザーからprivate spaceにあれこれする 44 | 45 | - フレームワークの仕組みを通さないとデータ参照したり、データ共有はできない 46 | - PhotoPicker 47 | - Intent.ACTION_SEND 48 | - Intent.ACTION_OPEN_DOCUMENT 49 | - etc. 50 | - private spaceのロックが解除されていないとできない 51 | 52 | 53 | ## アプリがprivate spaceで動作してるか判定できるのか 54 | 55 | - できない 56 | - private spaceがロックされてるのか、ロック解除されてるのか判断する方法はある 57 | - ただ判定するにはデフォルトのランチャーアプリに設定されている必要がある 58 | - ランチャーアプリ以外ではprivate spaceかどうかを判断する必要性がない設計になってる 59 | 60 | ## アプリがprivate spaceで動作してるか判定できるのか 61 | 62 | ![](./images/image2.png) 63 | 64 | 65 | ## アプリがprivate spaceで動作してるか判定できるのか 66 | 67 | - アプリをデフォルトのランチャーアプリにした上で実行 68 | 69 | ![](./images/image3.png) 70 | 71 | ## private spaceがロック中か、ロック解除されてるのか判定する 72 | 73 | - めっちゃ適用なランチャーアプリ作って、private spaceのロックを
解除するサンプル作りました 74 | - インストールしてランチャーのデフォルトアプリにすると動作する 75 | - https://github.com/operando/private-space-Launcher-sample 76 | 77 | 78 | ## private spaceをロックすると動作してたアプリはどうなるか 79 | 80 | - private space上にインストールされているアプリのプロセスがKillされる 81 | - なのでフォアグラウンドサービスなどもKillされる 82 | - ロックしたの動いてたら困るもんね 83 | 84 | ## private spaceの存在を隠せないケース例 85 | 86 | - adbで端末の情報あれこれ調べる 87 | - デバイスログ 88 | - デフォルトアプリに設定されたランチャーアプリ 89 | 90 | ## private space 公式ドキュメント 91 | 92 | - https://developer.android.com/about/versions/15/features?hl=ja#private-space 93 | - https://source.android.com/docs/security/features/private-space?hl=ja 94 | - https://support.google.com/android/answer/15341885?hl=ja 95 | 96 | 97 | ## ここまでが
公式ドキュメントに
書いてあること 98 | 99 | 100 | ## private space色々検証してみてわかったこと 101 | 102 | 103 | ## BOOT_COMPLETEDとLOCKED_BOOT_COMPLETEDが
ブロードキャストされない 104 | 105 | - private spaceをロック解除した際にこれらはブロードキャストされない 106 | - 複数ユーザーの場合、端末起動後にユーザーを切り替えた際には
ブロードキャストされる 107 | - ロック解除は端末起動ではないから…そうか…そうだよな…うーん… 108 | - これ地味に困る😨 109 | 110 | 111 | ## BOOT_COMPLETEDとLOCKED_BOOT_COMPLETEDが
ブロードキャストされない 112 | 113 | - ブロードキャストをスキップする実装になっている 114 | - finishUserUnlockedCompletedメソッド(BOOT_COMPLETED) 115 | - https://cs.android.com/android/platform/superproject/+/android15-qpr1-release:frameworks/base/services/core/java/com/android/server/am/UserController.java;l=939-945 116 | - sendLockedBootCompletedBroadcastメソッド(LOCKED_BOOT_COMPLETED) 117 | - https://cs.android.com/android/platform/superproject/+/android15-qpr1-release:frameworks/base/services/core/java/com/android/server/am/UserController.java;l=724-745 118 | 119 | 120 | ## なぜ困るのか 121 | 122 | - whooはBOOT_COMPLETEDをレシーブして、位置情報を取得する
フォアグラウンドサービスを起動してる 123 | - これが起動しないと、アプリを開くまで位置情報が取得できず
友達に位置情報を共有できない😂 124 | - BOOT_COMPLETEDを前提とした実装はちょっと危うい 125 | 126 | 127 | ## なんとかしてロック解除後 アプリ起動なしで何かしらの処理をできないか 128 | 129 | - WorkManagerやPush通知(FCM)などを使えばできるかも! 130 | - 検証はしてないです🙏 131 | 132 | 133 | ## private spaceの設定画面開けない問題 134 | 135 | - Unable to launch private space settings from 3rd-party launcher 136 | - https://issuetracker.google.com/issues/352276244 137 | - Android 15でPixel Launcherだと開けるのに、 3rd-partyだと
開けない 138 | - Android 16で開くためのメソッドが追加された 139 | - LauncherApps#getPrivateSpaceSettingsIntent 140 | - https://developer.android.com/reference/android/content/pm/LauncherApps#getPrivateSpaceSettingsIntent() 141 | 142 | 143 | ## private spaceロック中に電話が来たらどうなるか 144 | 145 | - private spaceにGoogle Meetをインストールして検証してみた 146 | - 結果は電話の着信が通知されない 147 | - ちゃんとprivate spaceが機能してる👍 148 | 149 | 150 | ## private spaceロック中に送られた通知はロック解除後
表示されるのか 151 | 152 | - されない 153 | - されないよ 154 | - されると思ったのに…そうか… 155 | 156 | ## private spaceでアプリインストール中にロックしたらどうなるか 157 | 158 | - インストール中は「インストール中だよ!」通知が出ている 159 | - ロックすると、数秒後にインストール中の通知が消える 160 | - ロック解除すると、インストールが再開される 161 | 162 | 163 | ## 音楽をバックグラウンドで再生したままロックして
ロック解除したら途中から再生されるか 164 | 165 | - されない 166 | - ロックするとアプリのプロセスがKillされるので、そうなるよね 167 | - ロック解除後にアプリインストールが再開するのは、システムサービス
関連だからと推測 168 | 169 | 170 | ## private spaceでクリップボードにコピーした内容を
システムユーザーで参照できるか 171 | 172 | - できた 173 | - その逆もできた 174 | - 通常のユーザー切り替えだとできない 175 | - どうしてできるのかはClipboardManagerの実装読んでみないとわからない 176 | - 利用する場合にちょっとだけ注意が必要な挙動 177 | 178 | 179 | 180 | ## Android Studioでビルドしたアプリをprivate spaceにインストールする 181 | 182 | - Install for all usersにチェックすれば、private spaceにインストールできる 183 | - How to run your app in Private Space from Android Studio 184 | - https://medium.com/@omeronce1995/how-to-run-your-app-in-private-space-from-android-studio-1c0101ef62c5 185 | 186 | ![](./images/image4.png) 187 | 188 | 189 | ## おまけ 190 | 191 | - ランチャーアプリでprivate space対応したい場合はLauncher3のコード読むのがおすすめ 192 | - https://cs.android.com/android/platform/superproject/main/+/main:packages/apps/Launcher3/ 193 | - https://cs.android.com/android/platform/superproject/main/+/main:packages/apps/Launcher3/src/com/android/launcher3/allapps/PrivateProfileManager.java 194 | - https://cs.android.com/android/platform/superproject/main/+/main:packages/apps/Launcher3/src/com/android/launcher3/allapps/PrivateSpaceSettingsButton.java 195 | 196 | 197 | ## おまけ 198 | 199 | - private spaceは通常のユーザー切り替えよりシームレスなので
アプリ開発時でも便利に使えそう 200 | - 複数アカウント用意して開発・デバッグするようなアプリは便利 201 | - 例えばwhooだと友達同士でメッセージやスタンプを送り合う機能が
あり、それのデバッグとか1端末で行えるのでよい 202 | 203 | ## おまけ 204 | 205 | - private spaceロックするとアプリのプロセスKillされる内部実装 206 | - ActivityManagerInternal#killForegroundAppsForUser 207 | - https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java;l=16606-16640 208 | - UserManagerService#setQuietModeEnabled 209 | - https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java;l=1937 210 | 211 | ## おまけ 212 | 213 | ![](./images/image5.png) 214 | 215 | - android.intent.action.PROFILE_UNAVAILABLEとandroid.intent.action.PROFILE_AVAILABLEを受け取るレシーバーをメインユーザーで動くアプリで設定してると、private spaceロック時、解除時に受け取れる 216 | - 権限がないと受け取ったレシーバーから取得できるユーザーがprivate spaceのユーザーなのかは判定できない 217 | - https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java;l=1758-1759 218 | 219 | ## まとめ と 感想 220 | 221 | - private spaceによりアプリの動作に影響するケースがある 222 | - private spaceに対応してないランチャーアプリ多い 223 | - 今回調査する上で内部実装も少し読んでみたけど、広範囲に影響してそうな
機能なので大変そうだなーと思った 224 | - あーそーゆーことね private space完全に理解した 225 | 226 | ## さいご告知です🙏 227 | 228 | - 2/12(水)19時からwhooのイベントやるので興味ある方ぜひ来てくれると嬉しいです! 229 | - https://linq.connpass.com/event/342607/ 230 | 231 | ![](./images/image6.png) 232 | 233 | ## Thanks!! -------------------------------------------------------------------------------- /Shibuya.apk51/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya.apk51/images/image.png -------------------------------------------------------------------------------- /Shibuya.apk51/images/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya.apk51/images/image2.png -------------------------------------------------------------------------------- /Shibuya.apk51/images/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya.apk51/images/image3.png -------------------------------------------------------------------------------- /Shibuya.apk51/images/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya.apk51/images/image4.png -------------------------------------------------------------------------------- /Shibuya.apk51/images/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya.apk51/images/image5.png -------------------------------------------------------------------------------- /Shibuya.apk51/images/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya.apk51/images/image6.png -------------------------------------------------------------------------------- /Shibuya.apk_10/README.md: -------------------------------------------------------------------------------- 1 | # Android + JSON-RPC 2.0 2 | 3 | ## [shibuya.apk #10](http://shibuya-apk.connpass.com/event/39433/) 4 | 5 | ## JSON-RPC?? 6 | 7 | 8 | ## JSON-RPC 9 | 10 | * JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol. 11 | 12 | ## JSON-RPC spec 13 | 14 | * http://www.jsonrpc.org/specification 15 | 16 | ## JSON-RPC 2.0 17 | 18 | ## RPC 19 | 20 | * gRPC 21 | * http://www.grpc.io/ 22 | * Go Conference 2016 SpringでgRPCの現状について発表してきました 23 | * http://tech.mercari.com/entry/2016/04/27/145227 24 | 25 | 26 | ## JSON-RPC 27 | 28 | * HTTP bodyのJSONでリクエストを記述する 29 | 30 | 31 | ## JSON-RPC Request 32 | 33 | * Request 34 | 35 | ```json 36 | { 37 | "jsonrpc": "2.0", 38 | "method": "subtract", 39 | "params": [ 40 | 42, 41 | 23 42 | ], 43 | "id": 1 44 | } 45 | ``` 46 | 47 | ## JSON-RPC Response 48 | 49 | * Response 50 | 51 | ```json 52 | { 53 | "jsonrpc": "2.0", 54 | "result": 19, 55 | "id": 1 56 | } 57 | ``` 58 | 59 | ## JSON-RPC Batch 60 | 61 | * 1回の通信で複数のリクエストを送れる 62 | 63 | 64 | ## JSON-RPC Request 65 | 66 | * Request 67 | 68 | ```json 69 | [ 70 | { 71 | "id": 1, 72 | "jsonrpc": "2.0", 73 | "method": "shibuya.apk", 74 | "params": { ... } 75 | }, 76 | { 77 | "id": 2, 78 | "jsonrpc": "2.0", 79 | "method": "shinobu.apk", 80 | "params": { ... } 81 | } 82 | ] 83 | ``` 84 | 85 | 86 | ## JSON-RPC Response 87 | 88 | * Response 89 | 90 | ```json 91 | [ 92 | { 93 | "id": 1, 94 | "jsonrpc": "2.0", 95 | "result": { ... } 96 | }, 97 | { 98 | "id": 2, 99 | "jsonrpc": "2.0", 100 | "result": { ... } 101 | } 102 | ] 103 | ``` 104 | 105 | ## 何に使うの?? 106 | 107 | * スクショ 108 | 109 | ## 何に使うの?? 110 | 111 | * 以下のリクエストが1回のリクエストでできる!! 112 | * タイムラインの投稿を取得 113 | * 現在地の座標を住所に変換する 114 | * バナーを取得する 115 | 116 | ## 何に使うの?? 117 | 118 | * タイムラインの投稿を取得 119 | * 現在地の座標を住所に変換する 120 | * バナーを取得する 121 | 122 | ## GET /home?? 123 | 124 | ## 複数の処理をまとめたAPIは仕様が壊れやすい 125 | 126 | ## JSON-RPC Batch 127 | 128 | * APIは個々の処理をメソッドとして定義 129 | * クライアント側で個々の処理を1つのリクエストにまとめて呼び出す 130 | 131 | ## JSON-RPC Request 132 | 133 | * Request 134 | 135 | ```json 136 | [ 137 | { 138 | "id": 1, 139 | "jsonrpc": "2.0", 140 | "method": "GetTimeline", 141 | "params": { ... } 142 | }, 143 | { 144 | "id": 2, 145 | "jsonrpc": "2.0", 146 | "method": "GetBanner", 147 | "params": { ... } 148 | } 149 | ] 150 | ``` 151 | 152 | ## JSON-RPC Response 153 | 154 | * Response 155 | 156 | ```json 157 | [ 158 | { 159 | "id": 1, 160 | "jsonrpc": "2.0", 161 | "result": { ... } 162 | }, 163 | { 164 | "id": 2, 165 | "jsonrpc": "2.0", 166 | "result": { ... } 167 | } 168 | ] 169 | ``` 170 | 171 | ## よさそう!! 172 | 173 | ## じゃAndroidで実装するか!! 174 | 175 | ## OkHttp使って試しに書いてみる Request 176 | 177 | * Request 178 | 179 | ```java 180 | OkHttpClient client; 181 | 182 | JSONObject json = new JSONObject(); 183 | JsonArray params = new JsonArray(); 184 | 185 | json.put("method","subtract"); 186 | params.put(42); 187 | params.put(23); 188 | json.put("params",params); 189 | 190 | RequestBody requestBody = RequestBody.create(MEDIA_TYPE, json.toString().getBytes()); 191 | 192 | Request request = new Request.Builder() 193 | .url("https://....") 194 | .post(requestBody) 195 | .build(); 196 | Response response = client.newCall(request).execute(); 197 | ``` 198 | 199 | ## OkHttp使って試しに書いてみる Response 200 | 201 | ```java 202 | Response response = client.newCall(request).execute(); 203 | // ... isSuccessfulのチェックとか... 204 | ResponseBody value = response.body(); 205 | 206 | JSONObject j = new JSONObject(value.string()); 207 | int result = j.getInt("result");// return 19 208 | ``` 209 | 210 | ## これイケてますかね?? 211 | 212 | ## イケてないですよね... 213 | 214 | ## いい感じのLibraryあるんじゃね...検索検索 215 | 216 | 217 | ## あまりない?? 218 | 219 | * jsonrpc4j 220 | * https://github.com/briandilley/jsonrpc4j 221 | * Batchに対応してない?? 222 | * retrofit-jsonrpc 223 | * https://github.com/segmentio/retrofit-jsonrpc 224 | * Batchに対応してない?? 225 | 226 | ## 結果 227 | 228 | ## 途方に暮れる日々... 229 | 230 | ## あーなんでこんなAPIになってるんだ... 231 | 232 | ## うぅ...僕はわるくない...(。-ω-) 233 | 234 | 235 | ## そうも言ってられない... 236 | 237 | 238 | ## そうだ!自分で作ればいいんだ! 239 | 240 | 241 | ## 雑に作りました! 242 | 243 | ## 作る前に考えたこと 244 | 245 | * 毎回同じ処理は書きたくない 246 | * リクエストの型が決まればレスポンスの型が決まる 247 | * リクエストとレスポンスを型で定義 248 | * Batch リクエストをいい感じに受け取りたい 249 | * Rxとか使っちゃう?? 250 | * 特定の通信ライブラリに依存しない 251 | 252 | ## JSON-RPCのクライアント実装で大変だったこと 253 | 254 | * Batch リクエストの受け取り方 255 | * エラーハンドリング 256 | * Retrofitの恩恵が受けられない… 257 | 258 | 259 | ## レスポンスのパターン 260 | 261 | * OK 1つのレスポンス 262 | * OK 複数のレスポンス(2,3つ) 263 | * NG 全レスポンスエラー 264 | * NG 一部のレスポンスエラー 265 | 266 | 267 | ## Batch リクエストの受け取り方 268 | 269 | * 複数のリクエストを作る 270 | * 作ったリクエストをまとめてAPIに投げる 271 | * 複数のレスポンスが返ってくる 272 | * ハンドリングしてレスポンスを通知する 273 | 274 | ## 複数のレスポンス...?? 275 | 276 | ## 複数のレスポンス...?? 277 | 278 | * List ?? 279 | * List ?? 280 | * List ?? 281 | 282 | ## どれもイケてない 283 | 284 | 285 | ## そうだ...Tupleだ!! 286 | 287 | 288 | ## 筋肉 2つ 289 | 290 | ```java 291 | @Getter 292 | public class Pair { 293 | private final F first; 294 | private final S second; 295 | 296 | private Pair(F first, S second) { 297 | this.first = first; 298 | this.second = second; 299 | } 300 | 301 | public static Pair create(F first, S second) { 302 | return new Pair<>(first, second); 303 | } 304 | } 305 | ``` 306 | 307 | ## 筋肉 3つ 308 | 309 | ```java 310 | @Getter 311 | public class Triplet { 312 | private final F first; 313 | private final S second; 314 | private final T thread; 315 | 316 | private Triplet(F first, S second, T thread) { 317 | this.first = first; 318 | this.second = second; 319 | this.thread = thread; 320 | } 321 | 322 | public static Triplet create(F first, S second, T thread) { 323 | return new Triplet<>(first, second, thread); 324 | } 325 | } 326 | ``` 327 | 328 | ## 複数のリクエストを作る 329 | 330 | ```java 331 | // リクエストとレスポンスをクラスとして定義 332 | // リクエスト : GetBanner レスポンス : GetBanner 333 | class GetBannerResponse { 334 | String url; 335 | } 336 | 337 | // リクエストの型が決まればレスポンスの型が決まる = RequestType<レスポンスの型> 338 | class GetBanner extends RequestType { 339 | @Override 340 | public String getMethod() { 341 | return "GetBanner"; 342 | } 343 | 344 | @Override 345 | protected Class getResponseType() { 346 | return GetBannerResponse.class; 347 | } 348 | } 349 | ``` 350 | 351 | ## 複数のリクエストを作る 352 | 353 | ```java 354 | // 同じように別APIのリクエストとレスポンスをクラスとして定義 355 | // リクエスト : GetTimeline レスポンス : GetTimelineResponse 356 | class GetTimelineResponse { 357 | List items; 358 | } 359 | 360 | 361 | class GetTimeline extends RequestType { 362 | private final long timelineId; 363 | 364 | GetTimeline(long timelineId) { 365 | this.timelineId = timelineId; 366 | } 367 | 368 | @Override 369 | public String getMethod() { 370 | return "GetTimeline"; 371 | } 372 | 373 | @Override 374 | protected Class getResponseType() { 375 | return GetTimelineResponse.class; 376 | } 377 | } 378 | ``` 379 | 380 | ## 作ったリクエストをまとめてAPIに投げる 381 | 382 | ```java 383 | GetTimeline getTimeline = new GetTimeline(1); 384 | GetBanner getBanner = new GetBanner(); 385 | 386 | RxApiClient rxApiClient = new RxApiClient(); 387 | 388 | // Observable>が返ってくうる 389 | rxApiClient.responseFrom(getTimeline,getBanner) 390 | .... 391 | ``` 392 | 393 | ## リクエストのクラスはJSONになってHTTP bodyに設定される 394 | 395 | ```json 396 | [ 397 | { 398 | "params": { 399 | "timelineId": 1 400 | }, 401 | "method": "GetTimeline", 402 | "jsonrpc": "2.0", 403 | "id": "1" 404 | }, 405 | { 406 | "params": {}, 407 | "method": "GetBanner", 408 | "jsonrpc": "2.0", 409 | "id": "2" 410 | } 411 | ] 412 | ``` 413 | 414 | 415 | ## 複数のレスポンスが返ってくる +
ハンドリングしてレスポンスを通知する 416 | 417 | 418 | ```java 419 | // 複数のレスポンスTupleに包んでRxに流す 420 | // responseFrom内でTupleに包む処理をしてる 421 | rxApiClient.responseFrom(getTimeline, getBanner) 422 | .subscribeOn(Schedulers.io()) 423 | .observeOn(AndroidSchedulers.mainThread()) 424 | .subscribe(new Action1>() { 425 | @Override 426 | public void call(Pair pair) { 427 | // Tupleからレスポンスを取り出す 428 | pair.getFirst(); // return GetTimelineResponse 429 | pair.getSecond(); // retrun GetBannerResponse 430 | } 431 | }); 432 | ``` 433 | -------------------------------------------------------------------------------- /Shibuya.apk_4/README.md: -------------------------------------------------------------------------------- 1 | # [shibuya.apk #4](http://shibuya-apk.connpass.com/event/21474/) 2 | 3 | # Slide 4 | 5 | * **[JobScheduler Code Reading](http://www.slideshare.net/shinobuokano7/jobscheduler-code-reading)** 6 | 7 | # 資料内のリンクとかJobSchedulerの電波メモ 8 | 9 | * [operando/JobScheduler-Code-Reading](https://github.com/operando/JobScheduler-Code-Reading) 10 | * [Shibuya.apk #4 資料リンク](https://github.com/operando/Notes/tree/master/Shibuya.apk_4) 11 | 12 | 13 | # JobScheduler Code Reading 14 | 15 | # About Me 16 | 17 | * Shinobu Okano([@operandoOS](https://twitter.com/operandoOS)) 18 | * Mercari, Inc. 19 | * 今週で23歳になりました!ありがとうございます! 20 | * 最近iPhone6s Plus買いました(笑) 21 | 22 | # [まったりAndroid Framework Code Reading #2](https://mandroidfcr.doorkeeper.jp/events/33925) 23 | 24 | * まったりAndroid Framework Code Reading #2やります! 25 | * メルカリでやります!きてね! 26 | * https://mandroidfcr.doorkeeper.jp/events/33925 27 | 28 | # Project Volta 29 | 30 | * 簡単に言ってバッテリー消費を削減するプロジェクト 31 | * Android Lで行われたもの 32 | * [Battery Historian](https://github.com/google/battery-historian) 33 | * [JobScheduler](http://developer.android.com/about/versions/android-5.0.html#Power) 34 | * [AlarmManagerが省電力化(4.4 KitKat)](http://developer.android.com/about/versions/android-4.4.html#BehaviorAlarms) 35 | 36 | 37 | # Google I/O 2014 - Introduction to Project Volta 38 | 39 | * [Google I/O 2014 - Introduction to Project Volta](https://www.youtube.com/watch?v=KzSKIpJepUw) 40 | 41 | 42 | # About JobScheduler 43 | 44 | * Android Lから導入されたAPI 45 | * 様々な条件のJobをスケジュールしてくれるAPI 46 | * 使うことで消費電力を意識した実装ができる 47 | * 開発者が頑張らなくていいAPI 48 | * JobSchedulerはAndroid Framework Services(System Service系) 49 | * マルチユーザ用にも設計されている(当たり前か) 50 | * Schedulerであって、Alarmではない 51 | * 特定の時間に実行!みたいな感じではない 52 | 53 | # JobSchedulerの使い方 54 | 55 | * [Android API21から追加されたJobSchedulerに
慣れていこう](http://blog.techfirm.co.jp/2015/10/19/android-api21%E3%81%8B%E3%82%89%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%81%9Fjobscheduler%E3%81%AB%E6%85%A3%E3%82%8C%E3%81%A6%E3%81%84%E3%81%93%E3%81%86/) 56 | * [Using the JobScheduler API on Android Lollipop](http://code.tutsplus.com/tutorials/using-the-jobscheduler-api-on-android-lollipop--cms-23562) 57 | 58 | # JobScheduler Sample 59 | 60 | * [googlesamples/android-JobScheduler](https://github.com/googlesamples/android-JobScheduler) 61 | * [operando/JobScheduler-Sample](https://github.com/operando/JobScheduler-Sample) 62 | * 実験用 63 | 64 | # Auto Backup - 条件 65 | 66 | * バックアップは24時間ごとに行われる 67 | * バックアップは充電中、WiFi接続、アイドル状態の3つの条件が満たされた時に行われる 68 | * この条件(24時間,充電中,WiFi接続,アイドル状態)を制御してるのがJobScheduler 69 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/backup/java/com/android/server/backup/FullBackupJob.java 70 | 71 | ##### http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/backup/java/com/android/server/backup/FullBackupJob.java 72 | 73 | ```java 74 | public static void schedule(Context ctx, long minDelay) { 75 | JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); 76 | JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService) 77 | .setRequiresDeviceIdle(true) 78 | .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) 79 | .setRequiresCharging(true); 80 | if (minDelay > 0) { 81 | builder.setMinimumLatency(minDelay); 82 | } 83 | js.schedule(builder.build()); 84 | } 85 | ``` 86 | 87 | 88 | # scheduleの流れ 89 | 90 | # JobScheduler.schedule(JobInfo) 91 | 92 | * JobScheduler.schedule(JobInfo) 93 | * プロセス間通信でJobSchedulerStub#scheduleを呼び出す 94 | * Jobの登録ができればJobScheduler.RESULT_SUCCESSが返ってくる。登録に失敗した場合JobScheduler.RESULT_FAILUREが返ってくる。 95 | * なので、Jobの登録ができたかどうかしっかり見てあげよう 96 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/JobSchedulerImpl.java#schedule 97 | 98 | # JobSchedulerStub#schedule 99 | 100 | * JobSchedulerStub#schedule 101 | * enforceValidJobRequestやcanPersistJobsでJob登録ができるかどうかとチェック 102 | * JobSchedulerService#scheduleを呼び出す 103 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#813 104 | 105 | # JobSchedulerService#schedule 106 | 107 | * JobSchedulerService#schedule 108 | * JobInfoとアプリのUIDでJobStatusを生成。Framework側ではJobInfoはJobStatusとして管理される 109 | * cancelJob + cancelJobImplで同じJobが登録されていたらcancelする(Job ID + UIDが同じJobStatus) 110 | * pendingとしてqueueに溜まってるJobもcancel。ActiveServices(実際に動いてるJob)を全部チェックして、同じJobがあればcancel処理を行う。 111 | 112 | # JobSchedulerService#stopTrackingJobs 113 | 114 | * JobStoreにある同じJobをremove 115 | * 各StateControllerから同じJobをremove(removeするにもJobStatusが各StateControllerの条件にあっているかどうかをチェックしてる) 116 | * 全JobStatusを管理するクラスとしてJobStoreが使われている 117 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#190 118 | 119 | # JobSchedulerService#startTrackingJob 120 | 121 | * 基本的にJobSchedulerService#stopTrackingJobと逆のことする(JobStatusのadd) 122 | * 各StateControllerにJobStatusをaddする(addするにもJobStatusが各StateControllerの条件にあっているかどうかをチェックしてる) 123 | * mReadyToRock(JobSchedulerの準備??)がtrueになっていないと、基本的にはaddもremoveもできない 124 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#373 125 | 126 | # JobSchedulerService#maybeQueueReadyJobsForExecutionLockedH 127 | 128 | * The state of at least one job has changed.(少なくとも一つのジョブの状態が変更された) 129 | * ready(実行可能)になっているjobがいくつ存在するかで決めているっぽい 130 | * Right now the policy is such: 131 | * If >1 of the ready jobs is idle mode we send all of them off 132 | * if more than 2 network connectivity jobs are ready we send them all off. 133 | * If more than 4 jobs total are ready we send them all off. 134 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#622 135 | 136 | # Demo 137 | 138 | * JobInfo.Builder#setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)のjobを1つずつ登録 139 | * 1個目のjobを登録したら、jobはREADYのままで止まっている(Pendingにも入ってない) 140 | * 2個目のjobを登録したら、jobがActiveになった 141 | * 上の条件に合致したので、jobをpending queueに移動させて、実行したのだと推測 142 | 143 | # デバイス再起動後も動くJobが作れる 144 | 145 | * JobInfo.Builder#setPersisted(true)でJobが再起動後も実行される 146 | * 開発者が再起動後に自分でまたJobを登録する必要がない 147 | * JobInfo.Builder#setExtras(PersistableBundle)で再起動後も値を引き継げる 148 | * 素晴らしい! 149 | 150 | #### サンプル(こんな感じ) 151 | 152 | ```java 153 | PersistableBundle persistableBundle = new PersistableBundle(); 154 | persistableBundle.putInt("id", i); 155 | JobInfo jobInfo = new JobInfo.Builder(i, serviceName) 156 | .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) 157 | .setPersisted(true) 158 | .setExtras(persistableBundle) 159 | .build(); 160 | scheduler.schedule(jobInfo); 161 | ``` 162 | 163 | # あれ?再起動後も引き継げるってことは? 164 | 165 | * Jobの情報を再起動時のためにどこかに保持する必要がある 166 | * ということは、ファイルとかに書き出さないとだよね? 167 | * おぉ!これは面白そう! 168 | 169 | # ということで、こいつ...どこかに保存してるぞ... 170 | 171 | * /data/system/job/jobs.xml 172 | * [JobStore](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobStore.java)というクラスがそこら辺管理してる 173 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobStore.java 174 | * JobSchedulerに新しいJob(Persisted = true)が追加された / Job(Persisted = true)が削除された際に、内容がSyncされる。 175 | * 書き込み処理は主にこれ 176 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobStore.java#WriteJobsMapToDiskRunnable 177 | 178 | # /data/system/job/jobs.xml 179 | 180 | ```xml 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | ``` 215 | 216 | 217 | # PersistableBundleの中身 218 | 219 | * JobにセットしたPersistableBundleの中身も書き込まれます 220 | * xmlへの書き込み処理はここでやってる 221 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/os/PersistableBundle.java#restoreFromXml 222 | * 書き込み処理はJobStore内から呼び出される 223 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobStore.java#608 224 | 225 | ```xml 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | ``` 234 | 235 | 236 | # PersistableBundleに書き込み処理 237 | 238 | * PersistableBundleの情報を保存する処理は、保存するXMLだけ用意してあげれば、どんなものでも使える汎用的なものっぽい。 239 | * PersistableBundle#restoreFromXmlがhideなので、サードパーティからは使えないけど・・・。 240 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/os/PersistableBundle.java#restoreFromXml 241 | 242 | 243 | # RAMサイズによって同時実行できるJobの数が変わる 244 | 245 | * System propertyのro.config.low_ram=trueの場合、**同時実行できるJobの数は1つ** 246 | * System propertyのro.config.low_ram=faseの場合、**同時実行できるJobの数は3つ** 247 | * ココらへん見るとJobの数についてわかる 248 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#77 249 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#352 250 | * ro.config.low_ramはAndroid4.4で導入された、メモリ搭載量が少ないターゲット向けの設定 251 | * https://source.android.com/devices/tech/config/low-ram.html 252 | * Android Wearとかはro.config.low_ram=trueかな? 253 | 254 | ###### http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#77 255 | 256 | ```java 257 | /** The number of concurrent jobs we run at one time. */ 258 | private static final int MAX_JOB_CONTEXTS_COUNT 259 | = ActivityManager.isLowRamDeviceStatic() ? 1 : 3; 260 | ``` 261 | 262 | ##### http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/ActivityManager.java#isLowRamDeviceStatic 263 | 264 | ```java 265 | // ActivityManager.java 266 | public static boolean isLowRamDeviceStatic() { 267 | return "true".equals(SystemProperties.get("ro.config.low_ram", "false")); 268 | } 269 | ``` 270 | 271 | # StateControllerの種類 272 | 273 | * JobManager 274 | * 各条件の監視をして、Jobの状態をコントロールする 275 | * [StateController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/StateController.java) (抽象クラス) 276 | * [AppIdleController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/AppIdleController.java) 277 | * [BatteryController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/BatteryController.java) 278 | * [ConnectivityController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/ConnectivityController.java) 279 | * [IdleController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/IdleController.java) 280 | * [JobStatus](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java) 281 | * [TimeController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/TimeController.java) 282 | * [Controllerの生成箇所](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#313) 283 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#313 284 | 285 | 286 | # Debugging JobScheduler 287 | 288 | * adb shell dumpsys jobscheduler 289 | * JobSchedulerに登録されているJobをDumpする 290 | * めっちゃ使う 291 | * adb logcat -s JobSchedulerService 292 | * JobSchedulerServiceのログ。あんまり出ないけど... 293 | * idle状態にするコマンド 294 | * adb shell dumpsys battery unplug 295 | * adb shell dumpsys deviceidle enable 296 | * adb shell dumpsys deviceidle step 297 | * adb shell dumpsys deviceidle force-idle 298 | 299 | 300 | # 面白コメント 301 | 302 | # // Let's go! 303 | 304 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#348 305 | 306 | # // GO GO GO! 307 | 308 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#367 309 | 310 | # 関連クラス 311 | 312 | * [JobSchedulerImpl](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/JobSchedulerImpl.java) 313 | 314 | * [/frameworks/base/core/java/android/app/job/](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/) 315 | * [IJobCallback.aidl](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/IJobCallback.aidl) 316 | * [IJobScheduler.aidl](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/IJobScheduler.aidl) 317 | * [IJobService.aidl](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/IJobService.aidl) 318 | * [JobInfo.aidl](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/JobInfo.aidl) 319 | * [JobInfo](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/JobInfo.java) 320 | * [JobParameters.aidl](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/JobParameters.aidl) 321 | * [JobParameters](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/JobParameters.java) 322 | * [JobScheduler](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/JobScheduler.java) 323 | * [JobService](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/job/JobService.java) 324 | 325 | * [/frameworks/base/services/core/java/com/android/server/job/](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/) 326 | * [JobCompletedListener](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobCompletedListener.java) 327 | * [JobSchedulerService](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java) 328 | * [JobServiceContext](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobServiceContext.java) 329 | * [JobStore](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobStore.java) 330 | * [StateChangedListener](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/StateChangedListener.java) 331 | 332 | * [/frameworks/base/services/core/java/com/android/server/job/controllers](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers) 333 | * [StateController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/StateController.java) 334 | * [AppIdleController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/AppIdleController.java) 335 | * [BatteryController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/BatteryController.java) 336 | * [ConnectivityController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/ConnectivityController.java) 337 | * [IdleController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/IdleController.java) 338 | * [JobStatus](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java) 339 | * [TimeController](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/controllers/TimeController.java) 340 | 341 | * Auto BackのJobSchedular 342 | * [FullBackupJob.java](http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/backup/java/com/android/server/backup/FullBackupJob.java) 343 | -------------------------------------------------------------------------------- /Shibuya_apk30/README.md: -------------------------------------------------------------------------------- 1 | # Firebase Test LabのRobo Testいい感じ 2 | 3 | 4 | ## Firebase Test Lab 5 | 6 | Test your app on devices hosted in a Google data center. 7 | 8 | ## Firebase Test Lab 9 | 10 | * 仮想デバイスと物理デバイス両方用意されてる 11 | * 今年iOSもサポートされた 12 | * Androidだと以下のテストができる 13 | * Instrumentation tests 14 | * Robo Test 15 | * Game loop test 16 | 17 | 18 | ## Robo Test 19 | 20 | Robo test analyzes the structure of your app's UI and then explores it methodically, automatically simulating user activities. 21 | 22 | ## Robo Test 23 | 24 | * 公式ドキュメント 25 | * https://firebase.google.com/docs/test-lab/android/robo-ux-test 26 | 27 | 28 | ## なぜ Robo Testを使い始めたのか 29 | 30 | * 発端はQAの方が試しに実行してくれた 31 | * 昔に使った時はあまり役にたたなかったけど、今回試してみたら良くなってた 32 | 33 | 34 | ## なぜ Robo Testを使い始めたのか 35 | 36 | * noteはAndroid 4系までサポートしてるけど、社内にまともに動く4系端末が少ない 37 | * リグレッションテスト的に手動で色んな画面をチェックするのが面倒 38 | * テストコード書いてない 39 | * けど、なんか自動で色んな画面見てほしい 40 | 41 | 42 | ## 対応してるAPIレベル 43 | 44 | * APIレベル 18 〜 28 45 | * Jelly Bean MR2 〜 Pまで 46 | * 十分そう 47 | 48 | 49 | ## Robo Testの実行に必要なもの 50 | 51 | * テストしたいアプリのApk 52 | * Firebase Project 53 | * (コマンドラインから実行する場合はgcloud) 54 | 55 | 56 | ## 無料で使えます! 57 | 58 | * Firebaseの料金プランがSparkプラン or Flameプランの場合は、ある程度無料で使えます 59 | * ちょっと試す分には十分使えます 60 | 61 | 62 | ## お金を払えばもっと使えます! 63 | 64 | * Firebaseの料金プランがBlazeプランの場合は、お金はかかりますが無制限で使えます 65 | * noteはBlazeプランでFirebase test labを使ってます 66 | 67 | 68 | ## Pricing 69 | 70 | * 料金の詳細は以下を参照 71 | * https://firebase.google.com/docs/test-lab/android/overview#billing 72 | 73 | 74 | ## noteでのFirebase test labの先月の使用料 75 | 76 | * 物理デバイスを2時間ちょっと使って 534円 77 | * 仮想デバイスは数十分使って 0円 78 | * 安い!! 79 | * Robo Testしか使ってない 80 | 81 | 82 | ## 使う上で知っておくといいこと 83 | 84 | * Robo Testのタイムアウト 85 | * カスタムログイン 86 | 87 | 88 | ## Robo Testのタイムアウト 89 | 90 | * Robo テストを実行する時間 91 | * noteでは5分に設定してる 92 | * まずは短くはじめて、結果を見て徐々にアプリに最適な時間を見つけるのが良さそう 93 | 94 | 95 | ## カスタムログイン 96 | 97 | * ログインが必要な画面や機能がある場合に使う 98 | * ログイン画面のid/passwordに入れる値を定義する 99 | * Robo Testがログイン画面にきたら、それぞれのEditTextに定義した値を入れ、ログインしてくれる 100 | 101 | 102 | ## カスタムログイン 103 | 104 | * これ定義しておかないと「あれ?ログイン画面 全然 突破できてない!ダメじゃん!」ってなるので、定義しておきましょう 105 | 106 | 107 | ## Demo 108 | 109 | 110 | ## Test Report 111 | 112 | 113 | ## 結果がシンプル 114 | 115 | ![](./images/image1.png) 116 | 117 | 118 | ## non-SDK interfaces使ってるところ出してくれる 119 | 120 | * APIレベル 28以上で動かすと出してくれる 121 | 122 | ![](./images/image2.png) 123 | 124 | 125 | ## パフォーマンスも出してくれる 126 | 127 | ![](./images/image3.png) 128 | 129 | 130 | ## パフォーマンスも出してくれる 131 | 132 | ![](./images/image4.png) 133 | 134 | 135 | ## パフォーマンスも出してくれる 136 | 137 | * Roboの操作動画とSyncしてそれぞれのグラフがどうなってるのか見れるのよい 138 | 139 | ![](./images/image5.png) 140 | 141 | 142 | ## Robo TestでクラッシュしたらStackTrace出してくれる 143 | 144 | ![](./images/image6.png) 145 | 146 | 147 | ## Robo TestでクラッシュしたらStackTrace出してくれる 148 | 149 | * StackTrace見るとRobo Testはespressoを使ってアプリの操作をしてることがわかる 150 | 151 | 152 | 153 | ## テストの結果がGCSに保存される 154 | 155 | * 操作ログのJSON 156 | * Robo script 157 | * このログを使えば、同じ操作のRobo Testができる 158 | * Logcat 159 | * Robo Test実行時の端末のLogcat 160 | 161 | 162 | ## テストの結果がGCSに保存される 163 | 164 | * Roboが操作した動画 165 | * スクリーンショット 166 | * クロールグラフ 167 | * Robo Testの操作から作成される画面遷移 168 | * これなかなかすごい 169 | 170 | ## クロールグラフ 171 | 172 | 173 | ![](./images/image7.png) 174 | 175 | 176 | ## Robo Testをいつ実行してるのか 177 | 178 | * noteではリリース前のQAを始める時に、複数バージョン、複数端末で実行してる 179 | * どれで実行するかどかのテンプレートを作れるので、そのテンプレートを使って毎回実行すると楽 180 | * Robo scriptはまだ使ってないので、操作は毎回ランダム操作 181 | 182 | 183 | ## 今度どうしたいか 184 | 185 | * Releaseブランチを作ったら、CI上から自動でRobo Test実行してほしい 186 | * 今はgcloudかFirebase Projectポチポチで実行してる 187 | * Robo scriptを使って、決められた操作を実行できるようにする 188 | * 新しい機能とか作ったらRobo scriptメンテする必要ありそうなのでどうしよう🤔 189 | * 運用してる方いたら知見ください🙏 190 | 191 | 192 | 193 | ## おまけ 194 | 195 | 196 | ## apkさえあれば… 197 | 198 | * 自分たちが作ってるアプリじゃなくても
Robo Test走らせられる🤫 199 | * やらないでね🙅‍ 200 | 201 | 202 | ## gcloudでRobo Testを実行 203 | 204 | * gcloudをインストールする 205 | * https://cloud.google.com/sdk/docs/downloads-interactive 206 | 207 | 208 | 209 | ## gcloudからRobo Testを実行 210 | 211 | * こんな感じのコマンドで実行 212 | 213 | ```bash 214 | gcloud firebase test android run \ 215 | --type robo \ 216 | --app \ 217 | --device model=Pixel2,version=28,locale=ja_JP,orientation=portrait \ 218 | --timeout 90s 219 | ``` 220 | 221 | 222 | 223 | ## まとめ 224 | 225 | 226 | * Robo Testはよい 227 | * 簡単に使い始められる 228 | * Test Reportが充実してるのも嬉しい 229 | * CIとかにも組み込めるのよい 230 | 231 | ## Thanks!! 232 | -------------------------------------------------------------------------------- /Shibuya_apk30/images/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya_apk30/images/image1.png -------------------------------------------------------------------------------- /Shibuya_apk30/images/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya_apk30/images/image2.png -------------------------------------------------------------------------------- /Shibuya_apk30/images/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya_apk30/images/image3.png -------------------------------------------------------------------------------- /Shibuya_apk30/images/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya_apk30/images/image4.png -------------------------------------------------------------------------------- /Shibuya_apk30/images/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya_apk30/images/image5.png -------------------------------------------------------------------------------- /Shibuya_apk30/images/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya_apk30/images/image6.png -------------------------------------------------------------------------------- /Shibuya_apk30/images/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Shibuya_apk30/images/image7.png -------------------------------------------------------------------------------- /Souzoh_Android_Talk_2/Contributeしてない俺がDroidKaigiアプリについてゴニョゴニョ話す会.md: -------------------------------------------------------------------------------- 1 | # Contributeしてない俺がDroidKaigiアプリについてゴニョゴニョ話す会 2 | 3 | ## スライド 4 | 5 | * https://speakerdeck.com/operando/contributesitenaian-kadroidkaigiahurinituitekoniyokoniyohua-suhui 6 | 7 | ## DroidKaigiアプリ 8 | 9 | * https://github.com/konifar/droidkaigi2018-flutter 10 | * https://github.com/DroidKaigi/conference-app-2018 11 | * https://github.com/kikuchy/DroidKaigi2018iOS 12 | 13 | ## DroidKaigiアプリ 14 | 15 | * 今日話すのはDroidKaigi/conference-app-2018 16 | 17 | 18 | ## 合わせて読みたい! 19 | 20 | * DroidKaigi 2018 App Architecture by takahirom 21 | * https://speakerdeck.com/takahirom/droidkaigi-2018-app-architecture 22 | * DroidKaigi アプリの内部を見る by tatsuhama50 23 | * https://www.slideshare.net/kenichitatsuhama/droidkaigi-88921455 24 | 25 | 26 | ## CircleCIのイメージは公式ので良さそう 27 | 28 | * きっと公式イメージをFROMで指定して、rubyを入れてるのかな? 29 | 30 | ```yaml 31 | jobs: 32 | build: 33 | docker: 34 | - image: punchdrunker/android-27-ruby 35 | ``` 36 | 37 | ## CircleCIのイメージは公式ので良さそう 38 | 39 | * 実は公式のイメージにもRubyは入ってる! 40 | * https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/android/images/api-27-alpha/Dockerfile#L125-L134 41 | 42 | 43 | ## CircleCIのImage 44 | 45 | * CircleCIが提供してるImageのDockerfileはGithubにまとまってる 46 | * https://github.com/CircleCI-Public/circleci-dockerfiles 47 | * AndroidのDockerfileももちろんあるよ 48 | * https://github.com/CircleCI-Public/circleci-dockerfiles/tree/master/android/images 49 | * circleci/android:api-27-alphaのDockerfileなら以下 50 | * https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/android/images/api-27-alpha/Dockerfile 51 | 52 | 53 | ## ページを保持してくれ!頼む! 54 | 55 | * SearchFragmentはViewPagerとTabLayoutの構成 56 | * Speakerタブに移動して、Sessionタブを開くとPageが再構築になる 57 | * スクロールしてた位置変わっちゃう 58 | * Sessionタブに切り替える時に若干もっさりする 59 | 60 | 61 | ## ページを保持してくれ!頼む! 62 | 63 | * そこでViewPagerのoffscreenPageLimitですよね! 64 | * offscreenのlimitを変更する 65 | * デフォルトでは1 66 | * デフォルト 1なので、Speakerタブに移動するとSessionタブが消える 67 | 68 | 69 | ## ページを保持してくれ!頼む! 70 | 71 | * Speakerタブに移動してもSessionタブが消えないようにしたい! 72 | * offscreenPageLimitを2にすればよさそう! 73 | * binding.sessionsViewPager.offscreenPageLimit = 2 74 | 75 | 76 | ## ページ保持できた! 77 | 78 | * やったね! 79 | * ページ数がどれくらいかわかってるなら最適化するほうがいい 80 | * ページの保持する分、メモリを使うので注意 81 | 82 | 83 | ## ViewPager#offscreenPageLimit 84 | 85 | * ViewPager#offscreenPageLimit API Document 86 | * https://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int) 87 | 88 | 89 | ## OkHttpのLogはリリース版は出さない方がいい! 90 | 91 | ![](./images/1.png) 92 | 93 | ![](./images/2.png) 94 | 95 | ![](./images/3.png) 96 | 97 | ![](./images/4.png) 98 | 99 | ![](./images/5.png) 100 | 101 | ![](./images/6.png) 102 | 103 | 104 | ## OkHttpのLogはリリース版は出さない方がいい! 105 | 106 | * リリース版のアプリではHttpLoggingInterceptorをInterceptorに設定しない方がいい 107 | * またはNONEに設定する 108 | * https://square.github.io/okhttp/3.x/logging-interceptor/okhttp3/logging/HttpLoggingInterceptor.Level.html 109 | * OkHttpの限らず、Logcatに流す内容はマジで気をつけてください! 110 | 111 | 112 | ## タブ タップした時にListの先頭に戻るのいいよね! 113 | 114 | * またまたSearchFragmentさんです 115 | * TabLayout.OnTabSelectedListenerを使って、タップイベントを取ってる 116 | * タブがタップされると、ViewPagerにアタッチされてるFragmentにタッチイベントが伝わる 117 | * FragmentのRecyclerViewにsmoothScrollToPosition(0)して、先頭までスクロールさせる 118 | 119 | 120 | ## タブ タップした時にListの先頭に戻るのいいよね! 121 | 122 | * 実装簡単だけど、めっちゃ便利になるので気に入ったらみんな実装してみてね! 123 | * メルカリ カウルでも似たような実装してるよ! 124 | 125 | 126 | ## @CheckResult Annotation 127 | 128 | * APIとかDBとかRepositoryの戻り値とかに
ちょいちょいつけられてた 129 | * DroidKaigiアプリで使われてるところ 130 | * https://github.com/DroidKaigi/conference-app-2018/search?q=CheckResult&type=Code&utf8=%E2%9C%93 131 | 132 | 133 | ## @CheckResult Annotation 公式から説明引用 134 | 135 | * “メソッドの結果または戻り値が実際に使用されているかどうかを検証するには @CheckResult アノテーションを使用します。

すべての非 void メソッドに @CheckResult アノテーションを付けるのではなく、複雑なメソッドの結果を明確にするためにアノテーションを追加します。” 136 | 137 | 138 | ## @CheckResult Annotation 公式から説明引用 139 | 140 | * “たとえば、経験の浅い Java デベロッパーは、.trim() が元の文字列から空白を削除するものだと勘違いすることがあります。メソッドに @CheckResult アノテーションを付けると、呼び出し元で .trim() の戻り値を一切使用していない場合に警告が出ます。” 141 | 142 | 143 | ## @CheckResult Annotation 144 | 145 | * https://developer.android.com/studio/write/annotations.html#check-result 146 | * https://developer.android.com/reference/android/support/annotation/CheckResult.html 147 | 148 | 149 | ## 国際化を意識したNotification Channel 150 | 151 | * Notification Channelとは? 152 | * 通知をChannelという単位にカテゴライズしよう!的な 153 | * 詳しくはドキュメント読んで! 154 | * https://developer.android.com/guide/topics/ui/notifiers/notifications.html#ManageChannels 155 | 156 | 157 | ## なぜ国際化を意識しないといけないのか 158 | 159 | * NotificationChannelをnewする時のnameはユーザに見えるチャンネルの概要的なやつ 160 | * これ設定アプリとかがresourceから出すわけではない 161 | * Channelを生成した時の言語のリソースに依存するってこと 162 | * 日本語設定でChannelを作成して、英語設定にするとChannelの説明が日本語になるという問題が起きる 163 | 164 | 165 | ## 国際化を意識したNotification Channel 166 | 167 | * 言語設定が変わったタイミングでChannelを作り直す 168 | * android.intent.action.LOCALE_CHANGEDをBroadcastReceiverでフックする 169 | * そのタイミングでチャンネルを作り直す 170 | * NotificationManager.createNotificationChannelは、同じChannel IDに対して再度生成を呼び出すとnameやdescriptionを更新できる 171 | 172 | 173 | ## 国際化を意識したNotification Channel 174 | 175 | * このことちゃんとドキュメントにも書いてある 176 | * https://developer.android.com/reference/android/app/NotificationChannel.html#NotificationChannel(java.lang.String, java.lang.CharSequence, int) 177 | 178 | 179 | ## 国際化を意識したNotification Channel 180 | 181 | * "You can rename this channel when the system locale changes by listening for the ACTION_LOCALE_CHANGED broadcast." 182 | 183 | 184 | ## 国際化を意識したNotification Channel 185 | 186 | * Incomplete Implementation of Notification Channel 187 | * https://github.com/DroidKaigi/conference-app-2018/pull/406 188 | * 【Android O】通知チャンネルを国際化する 189 | * https://qiita.com/Shiozawa/items/095e77d38fc00681e898 190 | 191 | 192 | ## DrawerLayout 193 | 194 | * よくできてる! 195 | * しかもどの画面でもDrawer出せるようになってる! 196 | * Googleが推奨??してる動くなのでよい 197 | 198 | 199 | ## resValue 200 | 201 | * GradleからResouceも生成できる! 202 | * 便利! 203 | * `resValue("string", "app_name", "DroidKaigi 2018 Dev")` 204 | 205 | 206 | ## resValue 207 | 208 | * app/build/generated/res/resValues/debug/values配下に生成される 209 | 210 | ```xml 211 | 212 | 213 | 214 | 215 | 216 | 217 | 1.0.0-debug 218 | 219 | DroidKaigi 2018 Dev 220 | 221 | 222 | ``` 223 | 224 | ## BindingAdapter 225 | 226 | * TextBinding.ktになるほどーっていうのあった! 227 | * android:textでDate渡せるようにする実装! 228 | 229 | ```kotlin 230 | @BindingAdapter(value = ["android:text"]) 231 | fun TextView.setDateText(date: Date?) { 232 | date ?: return 233 | text = date.toReadableDateTimeString() 234 | } 235 | ``` 236 | 237 | 238 | ## あとなんかアプリクラッシュしたw 239 | 240 | ```java 241 | Shutting down VM 242 | FATAL EXCEPTION: main 243 | Process: io.github.droidkaigi.confsched2018, PID: 11577 244 | b.a 245 | at io.github.droidkaigi.confsched2018.presentation.feed.a.a$a.onPreDraw(FeedItem.kt:58) 246 | at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:977) 247 | at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2349) 248 | at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1392) 249 | at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6752) 250 | at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911) 251 | at android.view.Choreographer.doCallbacks(Choreographer.java:723) 252 | at android.view.Choreographer.doFrame(Choreographer.java:658) 253 | at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 254 | at android.os.Handler.handleCallback(Handler.java:790) 255 | at android.os.Handler.dispatchMessage(Handler.java:99) 256 | at android.os.Looper.loop(Looper.java:164) 257 | at android.app.ActivityThread.main(ActivityThread.java:6494) 258 | at java.lang.reflect.Method.invoke(Native Method) 259 | at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 260 | at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 261 | ``` 262 | 263 | 264 | ## さらに読むと面白そうなところ 265 | 266 | * Mapperいいっすね 267 | * Room 268 | * https://developer.android.com/training/data-storage/room/index.html 269 | * `binding.prevSession = prevSession`と`binding.nextSession = nextSession` 270 | * RTL対応 271 | 272 | 273 | ## さらに読むと面白そうなところ 274 | 275 | * Firebase Firestore 276 | * https://firebase.google.com/docs/firestore/ 277 | * Firestore offlineは無効化してる 278 | * in memory cacheはある? 279 | * https://firebase.google.com/docs/firestore/manage-data/enable-offline?hl=ja 280 | * いいね!オフラインの状態で開くとアプリのProcess killするまで取得できない?? 281 | * オンラインにしてProcessレベルでアプリ立ち上げ直すと取得できる 282 | 283 | 284 | ## 話したかったけど時間の都合上話せなかったこと 285 | 286 | * EmojiCompat 287 | * Support LibraryのDownloadable FontsやEmojiCompatに対応したアプリを作ろう by takahirom 288 | * https://speakerdeck.com/takahirom/support-libraryfalsedownloadable-fontsyaemojicompatnidui-ying-sitaapuriwozuo-rou 289 | * Resultパターン 290 | * FeedItemなんかbugってる 291 | 292 | 293 | ## 話したかったけど時間の都合上話せなかったこと 294 | 295 | * NotificationHelper.kt 296 | * NotificationChannelTypeよさ 297 | * https://github.com/DroidKaigi/conference-app-2018/blob/master/app/src/main/java/io/github/droidkaigi/confsched2018/presentation/common/notification/NotificationHelper.kt 298 | * Gradle Versions Plugin 299 | * 入ってるけどCIとかでは使われてないので忘れがちだけどめっちゃ便利 300 | * https://github.com/ben-manes/gradle-versions-plugin 301 | * AlarmManager.setAndAllowWhileIdle + Doze 302 | * https://qiita.com/FumihikoSHIROYAMA/items/b1d6dbda120462d0e209 303 | 304 | 305 | ## 話したかったけど時間の都合上話せなかったこと 306 | 307 | * Open Source Notices 308 | * https://developers.google.com/android/guides/opensource 309 | * https://qiita.com/sho5nn/items/f63ebd7ccc0c86d98e4b 310 | * Kotlin DSL 311 | * https://github.com/gradle/kotlin-dsl 312 | * Kotlin + buildSrc for Better Gradle Dependency Management 313 | * https://handstandsam.com/2018/02/11/kotlin-buildsrc-for-better-gradle-dependency-management/ 314 | * マルチ モジュールだからバージョンの管理はこうした方が楽 315 | 316 | 317 | ## 話したかったけど時間の都合上話せなかったこと 318 | 319 | * MessageProcessorを返すのか 320 | * なるほどー 321 | * 処理をMessageProcessorごとに書けるので良さそう 322 | * 似たようなことをメルカリ カウルでもCustom URLでやってる 323 | 324 | ## さらにこの実装もあれば良かったー 325 | 326 | * Runtime Permission 327 | * いらないなら無理にやる必要ないよね 328 | 329 | 330 | ## DroidKaigi 2018 Flutter App 331 | 332 | * https://github.com/konifar/droidkaigi2018-flutter 333 | * git cloneしてからAndroidビルドできねーw 334 | 335 | 336 | ## Thanks 337 | -------------------------------------------------------------------------------- /Souzoh_Android_Talk_2/DroidKaigi発表 + 一部運営振り返り.md: -------------------------------------------------------------------------------- 1 | # DroidKaigi発表 + 一部運営振り返り 2 | 3 | ## 質問項目! 4 | 5 | ### 運営 6 | 7 | * 当日運営で一番テンパったことは? 8 | * そもそも1000人とか規模デカすぎじゃね 9 | * やりなおせるとしたらどこを変えたい? 10 | * ハンズオン・コードラボ部屋どうでした? 11 | * スポンサーブースでチェキやってたけど、他に案としてあがってた企画は? 12 | * スタッフって大変なの?スタッフやりながら、仕事や私生活ってどうやって運用してるの? 13 | 14 | #### 発表 15 | 16 | * 登壇前の前座の必要性について、どう思います? 17 | * 発表者控室ってどんな雰囲気なの?控室での面白い話ない? 18 | * なんでそのテーマで発表しようと思ったのか 19 | * 資料作るのどれくらい時間かかった?練習した?工夫したところある? 20 | * 登壇中ってどんな気持ちですか?どこ見て話してるんですか?どんなこと意識してますか? 21 | 22 | #### 今後の話っぽいところ 23 | 24 | * DroidKaigiの地方開催の予定は? 25 | * 次回のDroidKaigiはどこで開催しますか?希望と願望で! 26 | * 今回ニッチだったけど、次回のテーマは? 27 | 28 | ### 秘密の質問 29 | 30 | * DoridKaigi当日のスタッフ シフト事情 31 | * 日高さん以外 32 | * 正直、どうだった?文句なり、不満なりあれば今言った方がいいですよw 33 | * スタッフってセッション見れるの? 34 | * Organizerの後継者はいなの?または交代しないの? 35 | * カンファレンスのOrganizerってわりと変わるからこと毎度毎度新しいカンファレンスが作れる感じもするけど -------------------------------------------------------------------------------- /Souzoh_Android_Talk_2/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Souzoh_Android_Talk_2/images/1.png -------------------------------------------------------------------------------- /Souzoh_Android_Talk_2/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Souzoh_Android_Talk_2/images/2.png -------------------------------------------------------------------------------- /Souzoh_Android_Talk_2/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Souzoh_Android_Talk_2/images/3.png -------------------------------------------------------------------------------- /Souzoh_Android_Talk_2/images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Souzoh_Android_Talk_2/images/4.png -------------------------------------------------------------------------------- /Souzoh_Android_Talk_2/images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Souzoh_Android_Talk_2/images/5.png -------------------------------------------------------------------------------- /Souzoh_Android_Talk_2/images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/Souzoh_Android_Talk_2/images/6.png -------------------------------------------------------------------------------- /kyobashi.dex_2/README.md: -------------------------------------------------------------------------------- 1 | 2 | # ChromeとAndroidの過去・現在・未来 3 | 4 | # DroidKaigi 2016 5 | 6 | * みんな来てね! 7 | * https://droidkaigi.github.io/2016/ 8 | 9 | ![](./images/droidkaigi.png) 10 | 11 | # DroidKaigi 2016 12 | 13 | * 2日間セッションします! 14 | * Android Dev Tools Knowledge 15 | * 2/18 14:00-14:50 16 | * ChromeとAndroidの過去・現在・未来 17 | * 2/19 16:30-17:00 18 | 19 | # shinobu.apk #1 20 | 21 | * パネルディスカッション・一般参加募集中! 22 | * http://shinobu-apk.connpass.com/event/24921/ 23 | 24 | # shinobu.apk #1 25 | 26 | * shinobu.apkは、Shinobu Okanoと愉快な仲間たちが繰り広げるファンタジーな勉強会です。 27 | * shibuya.apkという、渋谷を中心に活動するAndroidアプリ開発者コミュニティの名前をtypoしたことによって生まれたものです。 28 | * 真面目に言うと、有志を募ってAndroidについてパネルディスカッションをする勉強会です。 29 | * Androidについてパネルディスカッションしよう! 30 | 31 | # 本題 32 | 33 | # ちなみに 34 | 35 | # 今日の発表DroidKaigiの前フリだからね? 36 | 37 | ## Chrome?? 38 | 39 | * Web Browser developed by Google 40 | * Blink Rendering Engine 41 | * V8 JavaScript Engine 42 | 43 | ## Chromium?? 44 | 45 | * open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web 46 | 47 | ## Chromeの技術を活用したアプリ開発 48 | 49 | * Chrome Custom Tabs 50 | * Web App Manifest 51 | * Service WorkersとWeb Push Notifications 52 | 53 | 54 | # Web App Manifest 55 | 56 | * アプリに関連するメタデータを記述したjsonファイルをサーバに置くことで、それらの情報をBrowserなど解釈し、Service Workerなどでプッシュ通知やHomeに追加が実現できる 57 | * https://www.w3.org/TR/appmanifest/ 58 | * メタデータを記述したjsonファイル = manifest.json 59 | * Chrome has had support for Manifests since version 38 for Android 60 | 61 | # Web App Manifest 62 | 63 | * 雑に言うと、このWebページはこーゆーもんやで 64 | * Homeに追加するならアイコンはこれ使ってくれ! 65 | * Push使いたいで! 66 | * アプリもあるから良かったらインストールして! 67 | * みたいな感じ... 68 | 69 | # あれ?Webの話じゃね?Android関係なくね? 70 | 71 | # Native app install banner 72 | 73 | * Webにネイティブアプリのインストールバナーを出すことができる 74 | * ネイティブアプリ = Android Application 75 | * 自身がリリースしたアプリ以外のインストールバナーも出せる! 76 | * support for Chrome 44 77 | 78 | # Native app install banner 79 | 80 | * You have a web app manifest file 81 | * short_nameと144x144のpng iconをtype image/pngとして書いておく 82 | * Your site is served over HTTPS 83 | * The user has visited your site twice over two separate days during the course of two weeks. 84 | 85 | # Native app install banner 86 | 87 | * manifest.jsonに以下のような書いてあげる 88 | 89 | ```json 90 | { 91 | "short_name": "Web Application Manifest Sample", 92 | "name": "Web Application Manifest Sample", 93 | "icons": [ 94 | { 95 | "src": "image/ic_android_black_48dp.png", 96 | "sizes": "144x144", 97 | "type": "image/png" 98 | } 99 | ], 100 | "prefer_related_applications": true, 101 | "related_applications": [ 102 | { 103 | "platform": "play", 104 | "id": "com.kouzoh.mercari" 105 | } 106 | ] 107 | } 108 | ``` 109 | 110 | # DEMO Native app install banner 111 | 112 | # Web Push Notifications 113 | 114 | * Push API 115 | * https://w3c.github.io/push-api/ 116 | * Notifications API 117 | * https://notifications.spec.whatwg.org/ 118 | * Service Worker 119 | * https://www.w3.org/TR/service-workers/ 120 | 121 | # Android Web History 122 | 123 | # Android 1.x 〜 Android 4.3.x 124 | 125 | * Based on the WebKit 126 | * Google I/O 2012 - Android WebView 127 | * https://android.googlesource.com/platform/external/chromium_org/+/kitkat-mr2-release/chrome/VERSION 128 | 129 | # Android 4.4.x 130 | * Chromemise Based WebView 131 | * KK MR1 Chrome M30 132 | * http://tools.oesf.biz/android-4.4.0_r1.0/xref/external/chromium_org/chrome/VERSION 133 | * KK MR3 Chrome M33 134 | * https://android.googlesource.com/platform/external/chromium_org/+/kitkat-mr2-release/chrome/VERSION 135 | * このバージョンごとのChrome Update作業は、Lの途中までは行われていたっぽい。L PreviewならChrome M37だった 136 | 137 | # Android 5.x 〜 138 | 139 | * Android System WebView 140 | * WebView apk 141 | * In Android 5.0 (Lollipop), the WebView has moved to an APK so it can be updated seperately to the Android platform. 142 | * https://play.google.com/store/apps/details?id=com.google.android.webview 143 | 144 | # Chrome ✕ Android 145 | 146 | * Chromeは今や巨大なソフトウェア 147 | * 世界では一番使われているWeb Browser 148 | * Androidも巨大なソフトウェア 149 | * 世界で一番使われているMobile OS 150 | 151 | # Chrome ✕ Android 152 | 153 | * 世界シェアTopを誇るソフトウェアプラットフォームを握るGoogle 154 | * Chrome OSとAndroidの統合した新しいOSのベータ版が2016年出る?みたいな噂はある 155 | * ChromeそのものがMobileの世界に与える影響が大きくなっている(個人的実感) 156 | 157 | 158 | a 159 | -------------------------------------------------------------------------------- /kyobashi.dex_2/images/droidkaigi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/kyobashi.dex_2/images/droidkaigi.png -------------------------------------------------------------------------------- /kyobashi.dex_3/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Gradle PluginとCIと俺 3 | 4 | 5 | ## 資料 6 | 7 | http://www.slideshare.net/shinobuokano7/gradle-pluginci-62464447 8 | 9 | ## CIしてますか?? 10 | 11 | 12 | ## CIで継続的にテストを回す?? 13 | 14 | 15 | ## そんな意識高い話じゃない!! 16 | 17 | ## [Travis CI](https://travis-ci.org/) 18 | 19 | https://travis-ci.org/ 20 | 21 | 22 | ## 俺が知ってるCIサービスの微妙なところ 23 | 24 | * 記述してる処理が正常に終わったか or 失敗したかの通知しかこない 25 | * ゴニョゴニョすれば細かいことはできるだろうけど難しそう... 26 | 27 | 28 | ## 何がしたかったか 29 | 30 | * GradleのTask単位での出力結果がほしい 31 | * その結果をSlackとかに通知してほしい 32 | * 人力でやるのは辛いのでCIでよしなな間隔でやってほしい 33 | 34 | 35 | ## GradleからSlackに通知したい! 36 | 37 | * できます! 38 | * gradle-slack-pluginならね! 39 | 40 | 41 | ## [gradle-versions-plugin](https://github.com/ben-manes/gradle-versions-plugin) (original) 42 | 43 | * https://github.com/ben-manes/gradle-versions-plugin 44 | 45 | 46 | ## [gradle-slack-plugin](https://github.com/operando/gradle-slack-plugin) (魔改造) 47 | 48 | * https://github.com/operando/gradle-slack-plugin 49 | 50 | 51 | ## gradle-slack-plugin setting 52 | 53 | ``` 54 | slack { 55 | url "slack web hock url" 56 | // 出力を通知したいtaskを書く 57 | dependsOnTasks 'dependencyUpdates' 58 | title 'gradle slack plugin title' 59 | enabled true or false 60 | } 61 | ``` 62 | 63 | ## じゃ何を通知するか 64 | 65 | * 定期的にSlackに通知して意味あるもの 66 | * 定期的に見ておいたほうがいいもの 67 | * 和むもの 68 | 69 | 70 | ## gradle-versions-plugin 71 | 72 | * Gradle plugin to discover dependency updates 73 | 74 | 75 | ## gradle-versions-plugin 76 | 77 | * gradle dependencyUpdates 78 | 79 | 80 | ## gradle-versions-plugin 81 | 82 | ![](./arts/gradle-version-plugin.png) 83 | 84 | 85 | ## gradle-slack-plugin + gradle-versions-plugin + CI 86 | 87 | * CI上でdependencyUpdates taskを実行 88 | * dependencyUpdates taskの出力結果をSlackに通知する 89 | * 簡単!! 90 | 91 | 92 | ## gradle-slack-plugin + gradle-versions-plugin + CI 93 | 94 | * 実行するタイミングは細かく設定可能 95 | * Pull RequestをMerge or masterにPushされた時のみ実行とか... 96 | * これはCIサービス側の設定で楽にできる 97 | * Travis CIの場合 98 | * .travis.yml 99 | * - if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./gradlew dependencyUpdates; fi 100 | 101 | 102 | ## Sample 103 | 104 | * Android Gradle Ci Sample 105 | * https://github.com/operando/AndroidGradleCiSample 106 | 107 | 108 | ## Demo 109 | 110 | 111 | ## こんな感じで通知くるよー 112 | 113 | ![](./arts/gradle-slack-plugin_and_gradle-version-plugin_and_ci_and_slack.png) 114 | 115 | 116 | ## その他に… 117 | 118 | * [dexcount-gradle-plugin](https://github.com/KeepSafe/dexcount-gradle-plugin)でメソッド数カウントして通知する 119 | * [gradle-android-apk-size-plugin](https://github.com/vanniktech/gradle-android-apk-size-plugin)でapkのサイズ調べて通知する 120 | * などなど… 121 | 122 | ## 応用編 123 | 124 | ## これ覚えてますか? 125 | 126 | ## [Gradle PluginとTwitterとズン ドコ キ・ヨ・シ!](http://www.slideshare.net/shinobuokano7/gradle-plugintwitter-59637926) 127 | 128 | * これ 129 | * http://www.slideshare.net/shinobuokano7/gradle-plugintwitter-59637926 130 | 131 | 132 | ## [gradle-zundokokiyoshi-plugin](https://github.com/operando/gradle-zundokokiyoshi-plugin) 133 | 134 | * https://github.com/operando/gradle-zundokokiyoshi-plugin 135 | 136 | 137 | ## gradle-zundokokiyoshi-plugin 138 | 139 | * gradle zungokokiyoshi 140 | 141 | 142 | ## gradle-zundokokiyoshi-plugin 143 | 144 | ![](./arts/gralde-zundokokiyoshi-plugin.png) 145 | 146 | ## どうするか 147 | 148 | * CI上でzungokokiyoshi taskを実行 149 | * zungokokiyoshi taskの出力結果をSlackに通知する 150 | * 簡単!! 151 | 152 | ## Demo 153 | 154 | ## こんな感じで通知くるよー 155 | 156 | ![](./arts/gralde-zundokokiyoshi-plugin_and_ci.png) 157 | 158 | ## さらにらに... 159 | 160 | ## [gradle-twitter-plugin](https://github.com/operando/gradle-twitter-plugin) 161 | 162 | * https://github.com/operando/gradle-twitter-plugin 163 | 164 | ## gradle-twitter-plugin 165 | 166 | * Gradleからツイートできる素晴らしいPlugin!! 167 | 168 | ## どうするか 169 | 170 | * CI上で.... 171 | 172 | ## と思ったけど... 173 | 174 | * なんかPluginの作りがあれであれなのでできなそう 175 | * 作ったやつのセンスが疑われる 176 | 177 | ## 色んなGradle Plugin 178 | 179 | * Android Dev Tools Knowledge - DroidKaigi 2016 180 | * http://www.slideshare.net/shinobuokano7/android-dev-tools-knowledge#33 181 | -------------------------------------------------------------------------------- /kyobashi.dex_3/arts/gradle-slack-plugin_and_gradle-version-plugin_and_ci_and_slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/kyobashi.dex_3/arts/gradle-slack-plugin_and_gradle-version-plugin_and_ci_and_slack.png -------------------------------------------------------------------------------- /kyobashi.dex_3/arts/gradle-version-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/kyobashi.dex_3/arts/gradle-version-plugin.png -------------------------------------------------------------------------------- /kyobashi.dex_3/arts/gralde-zundokokiyoshi-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/kyobashi.dex_3/arts/gralde-zundokokiyoshi-plugin.png -------------------------------------------------------------------------------- /kyobashi.dex_3/arts/gralde-zundokokiyoshi-plugin_and_ci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/kyobashi.dex_3/arts/gralde-zundokokiyoshi-plugin_and_ci.png -------------------------------------------------------------------------------- /note_engineer_meetup_1/README.md: -------------------------------------------------------------------------------- 1 | # Support Android 9 Pie 2 | 3 | * note engineer meetup #1の発表資料の書き起こしです 4 | * https://pieceofcake.connpass.com/event/101173/ 5 | 6 | 7 | ## スライド 8 | 9 | * https://speakerdeck.com/operando/support-android-9-pie 10 | 11 | 12 | ## note Androidチームについて 13 | 14 | * チームと言えど、現在1人 15 | * ~~俺が3人分になる…~~ 16 | * 成長の期待しかないチームです! 17 | 18 | ## 開発アプローチ 19 | 20 | 21 | ## note のアプリ、絶賛リニューアル中です 22 | 23 | ![](./images/app.png) 24 | 25 | https://note.mu/laprasdrum/n/nab0b64f3fa4b 26 | 27 | 28 | ## とはいえ... 29 | 30 | * リニューアルまで現行のアプリがアップデートされないことはお客様としては嬉しくない 31 | * アップデートがない = 改善されない + もう開発止まってるのかな?という不安 32 | * アプリを使ってるお客さまのこと忘れてないよ!というスタンスは大事 33 | 34 | 35 | ## iOSとAndroidで開発アプローチを変える 36 | 37 | * iOSとAndroidでは開発観点、アプリの機能や
提供できる体験などで課題が違う 38 | * 課題が違うならそれぞれ最適なアプローチで
やるのがベスト 39 | * Androidはすぐリリースできるし「まずは素早く試そう」の視点 40 | 41 | 42 | ## note Androidアプリ 過去3ヶ月の取り組み 43 | 44 | ## 何をしてきたか 45 | 46 | * 細かい使い勝手の改善 + 不具合修正 47 | * クラッシュ率の改善 48 | * Push通知を復活させる(涙なしには語れない) 49 | * リファクタリング? 50 | * いつかやらないといけないこと 51 | 52 | 53 | ## クラッシュ率の改善 54 | 55 | ![](./images/crash_report.png) 56 | 57 | 58 | ## リファクタリング? 59 | 60 | * とにかくいっぱいやりました 61 | * ?がついてるのは、察してください... 62 | * 現在 第二弾が終わったところで、まだまだ続きます 63 | 64 | 65 | ## いつかやらないといけないこと 66 | 67 | * Android O対応 ✅ 68 | * Android 9 Pie対応 ✅ 69 | * GCMからFCMへの移行 🏃 70 | 71 | 72 | ## 何を意識したか 73 | 74 | * 改善したものをなるべく早くリリースする 75 | * むやみにコードを見ない、書かない 76 | * コードは読まず、アプリをとにかく触る 77 | * 課題を見つける時間を多く取る 78 | * 1人だからこそやるべきことは早めにやっておく 79 | 80 | 81 | ## Suppo rt Android 9 Pie 82 | 83 | 84 | ## この資料でのSupport Android 9 Pieとは 85 | 86 | * Android 9による仕様変更で、アプリが
強制終了しないこと 87 | * アプリのtargetSdkVersionを28にする 88 | 89 | 90 | ## そもそもなぜSupportするのか? 91 | 92 | * 今後の Google Play でのアプリのセキュリティおよびパフォーマンスの改善について 93 | * https://developers-jp.googleblog.com/2017/12/improving-app-security-and-performance.html 94 | 95 | ## そもそもなぜSupportするのか? 96 | 97 | > “2018年の後半より、Playでは、新しいアプリやアプリのアップデートは最新のAndroid APIレベルをターゲットに指定することが義務づけられます。” 98 | 99 | 100 | ## そもそもなぜSupportするのか? 101 | 102 | > “これが必須となるのは、新規アプリは2018年8月、既存アプリのアップデートは2018年11月です。” 103 | > “2018年11月:既存のアプリのアップデートで、ターゲットAPIレベル26以降が必須になります。” 104 | 105 | ## そもそもなぜSupportするのか? 106 | 107 | * 要は、targetSdkVersionを26にしてAndroid O対応しないとアプリのアップデートがGoogle Playで配信できなくなるよってこと 108 | 109 | 110 | ## そもそもなぜSupportするのか? 111 | 112 | > “2019年以降:毎年、targetSdkVersionの要件が上がります。Androidの各デザートリリースの後1年以内に、新しいアプリとアプリのアップデートは、対応するAPIレベル以降にターゲットを指定することが義務づけられます。” 113 | 114 | 115 | ## つまり... 116 | 117 | * 早めにtargetSdkVersionを上げて、新しいOSバージョン向けの対応をしておいたほうがいい 118 | * アナウンスが出ても遠い先のことに感じて対応する気が起きない心理 119 | * 期限が近づいて急いで対応すると事故りやすい 120 | 121 | 122 | ## 対応の難易度はアプリによってまちまち 123 | 124 | * 使ってる機能、提供してる仕組みなどで対応の難易度が大きく変わる 125 | * 「使っていた機能がいきなり大変なこに!?」がわりと起こる 126 | * アプリエンジニアだけでは解決できない変更も起きる 127 | 128 | 129 | ## Android O Support Pull Request 130 | 131 | ![](./images/o.png) 132 | 133 | * そこそこ対応することがあった 134 | * コードもそこそこ書いた 135 | 136 | 137 | 138 | ## Android Pie Support Pull Request 139 | 140 | ![](./images/p.png) 141 | 142 | * 対応すべきことが少なかった 143 | * ほぼほぼコード書いてない 144 | 145 | 146 | 147 | ## まず何から始めるか 148 | 149 | * 公式ドキュメントやAndroid Developers Blogを熟読 150 | * targetSdkVersionに関係なく変更される動作targetSdkVersionに関係して変更される動作
それぞれを理解する 151 | 152 | 153 | ## まず何から始めるか 154 | 155 | * Android 9関連なら以下のドキュメントが熟読対象 156 | * https://developer.android.com/about/versions/pie/android-9.0-changes-all 157 | * https://developer.android.com/about/versions/pie/android-9.0-changes-28 158 | * Android Developers BlogにもAndroid 9向けの
解説記事がいくつかあるので、合わせて読んでおきたい 159 | 160 | 161 | ## まず何から始めるか 162 | 163 | * 熟読して自身のアプリに影響しそうな範囲にめぼしをつける 164 | * アプリだけで完結しない変更は早めに関係者に一声かけておく 165 | 166 | 167 | ## 個人的にやばそうと思ったAndroid 9で変更される動作 168 | 169 | 170 | ## Power management 171 | 172 | * App standby bucketsの導入 173 | * Battery saver improvements 174 | * https://developer.android.com/about/versions/pie/power 175 | 176 | 177 | ## App standby buckets 178 | 179 | * アプリの使用頻度によって、5つのpriority bucketsにアプリが振り分けられる仕組み 180 | * priorityが低いbucketに振り分けられるほど
アプリに動作制限がかかる 181 | 182 | 183 | ## Power management 184 | 185 | ![](./images/pp.png) 186 | 187 | 188 | ## Power management 189 | 190 | * Battery life最適化により起こる制限のまとめ 191 | * Power management restrictions 192 | * https://developer.android.com/topic/performance/power/power-details 193 | 194 | ## App standby buckets 195 | 196 | * どのbucketに割り振られるかのロジックは変更される可能性があるし、メーカー独自で変更できる?らしい 197 | * アプリはとにかくどのbucketに割り振られても、しっかり動作するように実装する 198 | 199 | 200 | ## Restrictions on use of non-SDK interfaces 201 | 202 | * Android P - Restrictions on non-SDK interfaces 203 | * https://speakerdeck.com/operando/android-p-restrictions-on-non-sdk-interfaces-1?slide=4 204 | * https://developer.android.com/about/versions/pie/restrictions-non-sdk-interfaces 205 | 206 | 207 | ## Network TLS enabled by default 208 | 209 | * httpでの通信がデフォルト不可能になる 210 | * iOSで言うところのATS(App Transport Security) 211 | * 動作確認した感じだとWebViewにも適用されてる気がする 212 | 213 | 214 | ## Android 9 Supportでnoteアプリが影響しそうな範囲として洗い出したもの 215 | 216 | * targetSdkVersionに関係なく変更される動作 217 | * Power management 218 | * Limited access to sensors in background 219 | * Restrictions on use of non-SDK interfaces 220 | 221 | 222 | ## Android 9 Supportでnoteアプリが影響しそうな範囲として洗い出したもの 223 | 224 | * targetSdkVersionに関係して変更される動作 225 | * Foreground services 226 | * Network TLS enabled by default 227 | * Apache HTTP client deprecation 228 | 229 | 230 | ## 実際に対応が必要だった変更 231 | 232 | * 2つだけで済んだ 233 | * Foreground services 234 | * Apache HTTP client deprecation 235 | 236 | ※ 対応はする必要なかったが、影響しそうな範囲として洗い出したものは、ドキュメントを読みながら動かしてみて動作確認はした 237 | 238 | 239 | ## Thanks!! 240 | -------------------------------------------------------------------------------- /note_engineer_meetup_1/images/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/note_engineer_meetup_1/images/app.png -------------------------------------------------------------------------------- /note_engineer_meetup_1/images/crash_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/note_engineer_meetup_1/images/crash_report.png -------------------------------------------------------------------------------- /note_engineer_meetup_1/images/o.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/note_engineer_meetup_1/images/o.png -------------------------------------------------------------------------------- /note_engineer_meetup_1/images/p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/note_engineer_meetup_1/images/p.png -------------------------------------------------------------------------------- /note_engineer_meetup_1/images/pp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/note_engineer_meetup_1/images/pp.png -------------------------------------------------------------------------------- /note_社内LT_2020-06-26/README.md: -------------------------------------------------------------------------------- 1 | # 設定だけでCircleCIの実行時間を短縮できるかもしれない話 2 | 3 | 4 | ## CircleCIのプラン 5 | 6 | - Performanceプランです 7 | - ざっくりいうと従量課金モデル 8 | - https://circleci.com/ja/pricing/ 9 | 10 | 11 | ## 細かいことは気にしないでください 12 | 13 | ## 設定だけでCircleCIの実行時間を短縮させる手段 14 | 15 | noteではそれぞれをうまく活用しています(DLC以外) 16 | 17 | - resource_class 18 | - cache 19 | - parallelism 20 | - Workflow 21 | - DLC 22 | 23 | 24 | ## 紹介するのは基本的にconfig.ymlを変更するだけで使えます 25 | 26 | ## cache 27 | 28 | - 成果物をcacheして、次のビルドにも活用する的なあれ 29 | - 変更がなければ同じ結果が得られる場面で活用できます 30 | - 依存関係のライブラリキャッシュとかまさにそれ 31 | - yarnとかBundlerとかそうですね 32 | 33 | 34 | ## resource_class 35 | 36 | https://circleci.com/docs/ja/2.0/configuration-reference/#resource_class 37 | 38 | - CIを実行するマシンのパワーを設定するもの 39 | - デフォルト medium(CPU 2 メモリ 4G) 40 | - マシンパワー上げるとビルドとか早くなる環境ではかなり役立つ 41 | - Androidでは xlarge(CPU 8 メモリ 16G)使用 42 | - jobごとに指定できるのもいい 43 | 44 | 45 | ## resource_class 46 | 47 | - マシンパワー上がるので、その分従量課金のお値段も上がります 48 | - 増し増しにしてもCPUとメモリを活用しきれない場合には不向き 49 | 50 | 51 | ## parallelism 52 | 53 | https://circleci.com/docs/ja/2.0/configuration-reference/#parallelism 54 | 55 | - jobの実行を複数のマシンで実行させたい場合に設定 56 | - 主にテストの並列実行で使われる 57 | - noteのRailsは現在 parallelism 3 58 | 59 | ## parallelism 60 | 61 | - ある程度までは並列化すると早くなる 62 | - 並列化しても多少の偏りは起きる 63 | - AマシンとBマシンで実行時間に差が出る 64 | - 差を調整する仕組みとして、Timing Dataが存在する 65 | - 並列化しすぎると時間短縮と従量課金のコストが見合わなくなる 66 | 67 | 68 | ## Running Tests in Parallel 69 | 70 | https://circleci.com/docs/2.0/parallelism-faster-jobs/ 71 | 72 | 73 | ## Workflow 74 | 75 | https://circleci.com/docs/ja/2.0/workflows/ 76 | 77 | - jobの実行順序を定義して、いい感じにjobを並列実行したりゴニョゴニョする 78 | - ちょっと複雑だけど慣れてくると便利 79 | - 逐次実行してたものを並列実行させられるようになると効果出てくる 80 | - 状況に応じて実行するWorkflowを変えたりすると便利 81 | 82 | ## Workflow例 83 | 84 | ![Workflow例](images/workflow.png) 85 | 86 | - ビルドして、その結果を2つのjobに共通して、jobを並列実行してる 87 | - 逐次実行より30minくらい早くなる 88 | 89 | 90 | ## Workflow 91 | 92 | - やりすぎ注意 93 | 94 | 95 | ## お金の話 96 | 97 | - 個人的には気にしなくてもいいと思ってる🤭 98 | - 無駄はダメ🙅🏽‍♂️ 99 | - お金より時間が短縮できる方が最高👍 100 | - Time is money💰 101 | 102 | 103 | ## まとめ 104 | 105 | - CIは生き物です、育成しましょう💪 106 | - 「遅くね?」と思ったその時がカイゼン時期🔧 107 | - お金をかければ早くなる…かも🙃 108 | -------------------------------------------------------------------------------- /note_社内LT_2020-06-26/images/workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/note_社内LT_2020-06-26/images/workflow.png -------------------------------------------------------------------------------- /otemachi_apk_2/README.md: -------------------------------------------------------------------------------- 1 | # Android Q Beta1 2 | 3 | ## 注意書き 4 | 5 | * 本資料はBeta1時点での話です 6 | * Beta1以降、仕様変更が行われる可能性があります 7 | * 自身でドキュメントと挙動を確認することをおすすめします 8 | 9 | ## Android Q Beta Sample 10 | 11 | * サンプルコード雑に書いてます 12 | * https://github.com/operando/Android-Q-Sample 13 | 14 | 15 | ## Android Q Beta 16 | 17 | * 公式ドキュメント 18 | * https://developer.android.com/preview 19 | * https://android-developers.googleblog.com/2019/03/introducing-android-q-beta.html 20 | 21 | 22 | 23 | ## Privacy in Android Q 24 | 25 | 26 | * Scoped storage 27 | * Background activity starts 28 | * App access to device location 29 | * Data & identifiers 30 | * Location & network 31 | 32 | 33 | ## Scoped storage 34 | 35 | * これが結構色々変わってる 36 | * 外部ストレージ使わなくても、知識としてはどう変わるのかを理解しておいた方がいい 37 | * https://developer.android.com/preview/privacy/scoped-storage 38 | 39 | ## Scoped storage 40 | 41 | * アプリ専用の sandboxストレージに作成したファイルは他のアプリからアクセスできなくなる 42 | * アプリ専用の sandboxストレージ 43 | * Context.getExternalFilesDirとかで取得できるディレクトリ 44 | * これまではWRITE_EXTERNAL_STORAGEパーミッションで他のアプリのファイルも扱えた? 45 | 46 | ## Scoped storage 47 | 48 | * アプリがアンイストールされても外部ストレージに
作ったファイルを残したいならshared collectionsに保存する 49 | * shared collections include 50 | * Photos & Videos 51 | * Music 52 | * Downloads 53 | 54 | ## Scoped storage 55 | 56 | * shared collectionに他アプリが作ったファイルを閲覧には、目的に応じて適切なPermissionが必要 57 | * shared collectionに他アプリが作ったファイルを変更には、特定のRoleが必要 58 | * 閲覧と変更を分けて考える 59 | 60 | 61 | ## Scoped storage 62 | 63 | * 外部ストレージを使わないアプリは関係ない話 64 | * 外部ストレージを使ってもアプリ専用のディレクトリだけしか使ってないアプリは影響しない話かも 65 | * Storage Access Frameworkが便利なのでできるだけ使っていきたい気持ち 66 | 67 | 68 | ## Background activity starts 69 | 70 | * バックグラウンドでActivityを起動することへ
の制限 71 | * 通知のタップなどユーザ操作以外でバックグラウンドからのActivity起動ができなくなる 72 | * 変な画面起動とかでやっている作業などが
中断されたりしなくて済むようになる 73 | 74 | 75 | ## 例えば... 76 | 77 | * IntentServiceからstartAcitivtyするとかできなくなる 78 | * ユーザ操作ではないので 79 | 80 | 81 | ## App access to device location 82 | 83 | * ユーザがバックグラウンドでの位置情報取得を許すかどうかを選択できるようになる 84 | * バックグラウンドで位置情報を取らないアプリは影響なし 85 | 86 | 87 | 88 | ## Android Q features and APIs 89 | 90 | * TLS 1.3 support 91 | * Wi-Fi Direct connection API 92 | * Roles 93 | * Settings panels 94 | 95 | 96 | 97 | ## Roles 98 | 99 | * ドキュメント 100 | * https://developer.android.com/preview/features/roles 101 | 102 | 103 | 104 | ## Roles 105 | 106 | * OSレベルでよく使われるユースケースごとにRoleを作った 107 | * Roleを与えられたアプリはRole特有の権限が付与される 108 | * 各RoleごとにRoleを与えられるアプリは1つ 109 | 110 | 111 | ## Roles defined in Android Q 112 | 113 | 114 | ![](./images/role.png) 115 | 116 | 117 | ## どうしてRoleが必要だったのか?(推測) 118 | 119 | * Android QのPrivacy周りの変更の影響を受けないような特権の仕組みが必要だったのかなーとか? 120 | * Privacyは守りつつ、ユーザに不便をかけないためとか? 121 | * ユーザが認めたアプリはある程度優遇される 122 | 123 | 124 | ## どうやってRoleを与えるか 125 | 126 | * Roleを付与してほしいアプリが、「Role付与してください!」とユーザにお願いする 127 | 128 | 129 | ## Roleの付与をリクエストする 130 | 131 | * RoleManager#createRequestRoleIntentで作成したIntentをstartActivityForResultする 132 | * onActivityResultでリクエストの結果を受け取る 133 | 134 | 135 | ## Roleの付与をリクエストする 136 | 137 | 138 | ```java 139 | RoleManager roleManager = getSystemService(RoleManager.class); 140 | if (!roleManager.isRoleAvailable(RoleManager.ROLE_MUSIC)) { 141 | return; 142 | } 143 | if (roleManager.isRoleHeld(RoleManager.ROLE_MUSIC)) { 144 | Log.d("RoleManager", "OK"); 145 | } else { 146 | Intent roleRequestIntent = roleManager.createRequestRoleIntent(RoleManager.ROLE_MUSIC); 147 | startActivityForResult(roleRequestIntent, 2); 148 | } 149 | ``` 150 | 151 | ## Roleの付与をリクエストする 152 | 153 | 154 | |Role|Role| 155 | |---|---| 156 | |![](./images/role_req1.png)|![](./images/role_req2.png)| 157 | 158 | 159 | 160 | ## Roles Tips 161 | 162 | * adb shell dumpsys roleで定義されているRoleや、各Roleを与えられたアプリが確認できる 163 | 164 | 165 | 166 | 167 | ## adb shell dumpsys role 168 | 169 | ``` 170 | ROLE MANAGER STATE (dumpsys role): 171 | { 172 | user_states={ 173 | user_id=0 174 | version=-1 175 | packages_hash=36952A4F6A5BFC8AF7A8F8A6025837C802AA548976DB456B6222A15ECB0C37FC 176 | roles=[ 177 | { 178 | name=android.app.role.CAR_MODE_DIALER_APP 179 | } 180 | { 181 | name=android.app.role.CALL_COMPANION_APP 182 | } 183 | { 184 | name=android.app.role.CALL_SCREENING_APP 185 | } 186 | { 187 | name=android.app.role.TEMPORARY_SMS_ACCESS 188 | } 189 | { 190 | name=android.app.role.PROXY_CALLING_APP 191 | } 192 | { 193 | name=android.app.role.SMS 194 | holders=com.google.android.apps.messaging 195 | } 196 | { 197 | name=android.app.role.DIALER 198 | } 199 | { 200 | name=android.app.role.MUSIC 201 | holders=com.google.android.music 202 | } 203 | { 204 | name=android.app.role.HOME 205 | } 206 | { 207 | name=android.app.role.CAR_PROJECTION 208 | } 209 | { 210 | name=android.app.role.GALLERY 211 | } 212 | { 213 | name=android.app.role.ASSISTANT 214 | } 215 | { 216 | name=android.app.role.EMERGENCY 217 | holders=com.android.emergency 218 | } 219 | { 220 | name=android.app.role.BROWSER 221 | holders=com.android.chrome 222 | } 223 | ] 224 | } 225 | } 226 | ``` 227 | 228 | 229 | 230 | ## Settings panels 231 | 232 | * 特定の設定をシームレスに表示できる 233 | * 例えば、NFCをONしたりするのに、設定アプリを開くのではなく、Settings Panelを開く 234 | * ユーザはアプリから離脱することなく、設定を変えられる 235 | 236 | 237 | ## ネットワークのSettings panelを開く 238 | 239 | 240 | ```kotlin 241 | val i = Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY) 242 | startActivityForResult(i) 243 | ``` 244 | 245 | ## ネットワークのSettings panelを開く 246 | 247 | ![](./images/setting_panel.png) 248 | 249 | 250 | ## Settings panels 251 | 252 | * UI部分がSliceで実装されてる 253 | * ラッパーがAndroidXで導入されるらしい 254 | 255 | 256 | ## Android Q Beta 257 | 258 | * 他にも色んな変更が入ってるので、ぜひ公式ドキュメント読んで、コードを書いて、挙動を確かめてみてください! 259 | * 公式ドキュメント 260 | * https://developer.android.com/preview 261 | 262 | 263 | ## 参考リンク 264 | 265 | * Scoped storage 266 | * https://developer.android.com/preview/privacy/scoped-storage 267 | * Roles 268 | * https://developer.android.com/preview/features/roles -------------------------------------------------------------------------------- /otemachi_apk_2/images/role.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/otemachi_apk_2/images/role.png -------------------------------------------------------------------------------- /otemachi_apk_2/images/role_req1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/otemachi_apk_2/images/role_req1.png -------------------------------------------------------------------------------- /otemachi_apk_2/images/role_req2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/otemachi_apk_2/images/role_req2.png -------------------------------------------------------------------------------- /otemachi_apk_2/images/setting_panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/otemachi_apk_2/images/setting_panel.png -------------------------------------------------------------------------------- /potatotips_23/README.md: -------------------------------------------------------------------------------- 1 | # [【第23回】potatotips(iOS/Android開発Tips共有会)](http://connpass.com/event/21750/) 2 | 3 | # Title 4 | -------------------------------------------------------------------------------- /potatotips_23/note.md: -------------------------------------------------------------------------------- 1 | 2 | # Slackに隕石という名のスクリーンショットを落下させる話 3 | 4 | # About me 5 | 6 | * Shinobu Okano(@operandoOS) 7 | * Mercari, Inc. 8 | * ハンバーグ食べたい... 9 | 10 | # まったりAndroid Framework Code Reading #2 11 | 12 | * https://mandroidfcr.doorkeeper.jp/events/33925 13 | 14 | 15 | # Meteoroid 16 | 17 | * https://github.com/operando/Meteoroid 18 | 19 | # Meteoroid 20 | 21 | ```java 22 | File uploadFile = new File(..); 23 | 24 | new Meteoroid.Builder() 25 | .token("your slack api token") 26 | .uploadFile(uploadFile) 27 | .channels("#general") 28 | .title("test titke") 29 | .initialComment("test comment") 30 | .build() 31 | .post(this); 32 | ``` 33 | 34 | # Meteoroid 35 | 36 | ```java 37 | allprojects { 38 | repositories { 39 | jcenter() 40 | maven { 41 | url "https://dl.bintray.com/operandoos/maven/" 42 | } 43 | } 44 | } 45 | 46 | compile 'com.os.operando.meteoroid:meteoroid:1.0.1' 47 | ``` 48 | 49 | # Meteor 50 | 51 | * https://github.com/operando/Meteor 52 | 53 | # Meteor 54 | 55 | 56 | # Meteorite 57 | 58 | * https://github.com/operando/Meteorite 59 | 60 | # Meteorite 61 | 62 | ```xml 63 | // your app's AndroidManifest.xml 64 | 65 | 68 | 69 | 74 | 75 | ..... 76 | 77 | 80 | 81 | 82 | ``` 83 | 84 | # Meteorite 85 | 86 | ```xml 87 | // your app's AndroidManifest.xml 88 | 89 | 90 | 91 | 95 | ``` 96 | 97 | 98 | # Meteorite 99 | 100 | ```java 101 | public class MyApplication extends Application { 102 | @Override 103 | public void onCreate() { 104 | super.onCreate(); 105 | Meteorite.init(this); 106 | } 107 | } 108 | ``` 109 | 110 | # Meteoroid 111 | 112 | ```java 113 | allprojects { 114 | repositories { 115 | jcenter() 116 | maven { 117 | url "https://dl.bintray.com/operandoos/maven/" 118 | } 119 | } 120 | } 121 | 122 | compile 'com.os.operando.meteorite:meteorite:1.0.1' 123 | ``` 124 | 125 | # Thanks! 126 | 127 | * Thanks! -------------------------------------------------------------------------------- /potatotips_52/README.md: -------------------------------------------------------------------------------- 1 | # Android P - Restrictions on non-SDK interfaces 2 | 3 | ## Slide 4 | 5 | https://speakerdeck.com/operando/android-p-restrictions-on-non-sdk-interfaces-1 6 | 7 | ## Android P Developer Preview 3 (Beta 2)時点のドキュメントを参考に書いてます 8 | 9 | 10 | ## Restrictions on non-SDK interfaces 11 | 12 | * Android Pから適用されるnon-SDKへの制限事項 13 | * 雑にいうとnon-SDKにアクセスするとExceptionが起きる...場合がある! 14 | * アプリだけではなく、ライブラリを作ってる人にも関係する話 15 | * この制限はtargetSdkVersion関係なくAndroid Pで動作するすべてのアプリに
適用される 16 | * 一部でtargetSdkVersionで異なる動作をする 17 | 18 | 19 | ## What are non-SDK interfaces? 20 | 21 | * They are Java fields and methods that are not part of the official Android SDK. 22 | 23 | 24 | ## What are non-SDK interfaces? 25 | 26 | * リフレクションを使ってアクセスするような fields and methods 27 | * Android frameworkのSDKドキュメントに記載されていないものはnon-SDKと考えて良さそう 28 | 29 | 30 | ## What are non-SDK interfaces? 31 | 32 | * Support LibraryなどGoogleが公式で出しているLibraryは現時点は対象外っぽい 33 | * あくまであれらはLibraryって扱いって話かな 34 | 35 | 36 | ## つまり 🤔 37 | 38 | * つまり、直接、リフレクション、またはJNI経由でnon-SDKを使用する場合に適用される制限ですよー 39 | 40 | ## Restrictions on non-SDK interfaces 41 | 42 | * 直接・リフレクション、またはJNI経由でnon-SDKを使用する場合に適用される制限ですよー 43 | * Android P未満の端末で動作するアプリではこの制限は適用されません 44 | 45 | 46 | ## Results of keeping non-SDK interfaces 47 | 48 | * アクセス手段とそれぞれの結果は表のようになる 49 | 50 | ![](images/non-sdk.png) 51 | 52 | 53 | ## Results of keeping non-SDK interfaces 54 | 55 | * non-SDKにアクセスするとErrorやExceptionが起きたり、リフレクションしてもnullを返して存在しないfields and methodsとして扱いますよー 56 | 57 | 58 | ## すべてのnon-SDKが使えなくなるの? 59 | 60 | 61 | ## そうではない 62 | 63 | 64 | ## non-SDKは3つのリストに分けられている 65 | 66 | * light-greylist 67 | * dark-greylist 68 | * blacklist 69 | 70 | 71 | ## non-SDKの各リストの違い 72 | 73 | * 各リストごとに定義されてるnon-SDK fields and methodsが違う 74 | * non-SDKへアクセスした時の動作が違う 75 | 76 | 77 | ## non-SDKの各リストの違い 78 | 79 | * リストのファイルは以下のAOSPにある 80 | * https://android.googlesource.com/platform/prebuilts/runtime/+/master/appcompat 81 | * hiddenapi-light-greylist.txt 82 | * hiddenapi-dark-greylist.txt 83 | * hiddenapi-blacklist.txt 84 | 85 | ## non-SDKの各リストの違い 86 | 87 | * ファイルにはずらっとnon-SDK fields and methodsが書いてある 88 | 89 | ![](images/non-sdk-list.png) 90 | 91 | 92 | ## light-greylist 93 | 94 | * まだ普通にアクセスできるnon-SDKが定義されている 95 | * 将来のバージョンでもアクセスを保証するものではない 96 | * いつかは使えなくなるかもねって話かな 97 | 98 | 99 | ## dark-greylist 100 | 101 | * アプリのtargetSdkVersionによって動作が異なる 102 | * targetSdkVersionがP未満(27以下)の場合 103 | * まだ普通にアクセスできるnon-SDKが定義されている 104 | * light-greylistと同じ感じ 105 | * targetSdkVersionがP以上(28以上)の場合 106 | * アクセスできないnon-SDKが定義されている 107 | * blacklistと同じ感じ 108 | 109 | 110 | ## blacklist 111 | 112 | * targetSdkVersionに関係なくアクセスできないnon-SDKが定義されている 113 | * アクセスするとExceptionが起きます 114 | * 要はこのリストに含まれるnon-SDKは使わない方がいい! 115 | 116 | 117 | ## Sampleプロジェクト書いてみた 118 | 119 | * https://github.com/operando/Android-P-Restrictions-on-non-SDK-interfaces-Sample 120 | 121 | 122 | ## Demo 123 | 124 | 125 | ## んで、結局なに対応したらいいの? 126 | 127 | * 自身が作ってるアプリがnon-SDKを使ってないかチェック 128 | * 使ってるライブラリがnon-SDKを使ってないかもチェック 129 | * 使っていたらどのlistに含まれるnon-SDKかチェック 130 | * dark-greylist or blacklistのnon-SDKだったら何か対応した方が良さそう 131 | * light-greylistのnon-SDKでも対応できるならやるべき 132 | 133 | 134 | ## 対応方法 135 | 136 | * non-SDKを使わないコードに書き直す 137 | * 適切に例外処理して、Android P未満では
動作するコードにする 138 | * Android Pでは動作をあきらめる 139 | * あきらめて踊る 140 | 141 | 142 | ## あきらめて踊る前に... 143 | 144 | * Androidのissue trackerにFeature Requestを出す 145 | * 使用してるnon-SDKの詳細なユースケースとか書いて出す 146 | * 再検討はするけど、絶対に承認されるわけではない 147 | * dark-greylistにあったものがlight-greylistになるとかはあるかも? 148 | 149 | 150 | ## あきらめて踊る前に... 151 | 152 | * Feature Requestの出し方はドキュメントにリンクある 153 | * https://developer.android.com/preview/restrictions-non-sdk-interfaces 154 | 155 | 156 | ## メジャーなライブラリにはissueが上がり始めてる 157 | 158 | * okhttp reflection meet Android P DP1 non-sdk restriction 159 | * https://github.com/square/okhttp/issues/3980 160 | * [ Important ] Violations on android P `Restrictions on non-SDK interfaces` 161 | * https://github.com/facebook/react-native/issues/19067 162 | 163 | 164 | ## ライブラリのメンテナーとしての対応 165 | 166 | * 基本アプリの時と同じチェックを行う 167 | * light-greylistのnon-SDKなら今すぐ対応しなくても大丈夫 168 | * とはいえ、今後の動作は保証されるわけではないので対応できるなら対応する 169 | 170 | 171 | ## ライブラリのメンテナーとしての対応 172 | 173 | ![](images/okhttp.png) 174 | 175 | 176 | ## React Nativのissue 177 | 178 | * [ Important ] Violations on android P `Restrictions on non-SDK interfaces` 179 | * https://github.com/facebook/react-native/issues/19067 180 | 181 | ## React Nativのissueで触れられてる部分のコード 182 | 183 | * リフレクションしてるね!いいね! 184 | * けど...TextViewのmCursorDrawableResはlight-greylistに含まれるnon-SDK fieldなので今のところはPでも動く 185 | 186 | ```java 187 | try { 188 | // Get the original cursor drawable resource. 189 | Field cursorDrawableResField = TextView.class.getDeclaredField("mCursorDrawableRes"); 190 | cursorDrawableResField.setAccessible(true); 191 | int drawableResId = cursorDrawableResField.getInt(view); 192 | ..... 193 | } catch (NoSuchFieldException ex) { 194 | // Ignore errors to avoid crashing if these private fields don't exist on modified 195 | // or future android versions. 196 | } 197 | ``` 198 | 199 | 200 | ## ライブラリにissueをあげるなら... 201 | 202 | * 使用されてるnon-SDKがどのlistに属するのか書く 203 | * non-SDKを使わなくても実装できる方法があれば書く 204 | * Androidのissue trackerにFeature Requestを出してもらうようにお願いする 205 | 206 | 207 | ## How can I enable access to non-SDK APIs? 208 | 209 | * adbでglobal settingをいじることで、動作を変えることができます 210 | 211 | ```bash 212 | adb shell settings put global hidden_api_policy_pre_p_apps 1 213 | adb shell settings put global hidden_api_policy_p_apps 1 214 | ``` 215 | 216 | ## How can I enable access to non-SDK APIs? 217 | 218 | * 指定する数字の意味は以下のとおり 219 | * 0: Disable non-SDK API usage detection. This will also disable logging, and also break the strict mode API, detectNonSdkApiUsage(). Not recommended. 220 | * 1: "Just warn" - permit access to all non-SDK APIs, but keep warnings in the log. The strict mode API will keep working. 221 | * 2: Disallow usage of dark grey and black listed APIs. 222 | * 3: Disallow usage of blacklisted APIs, but allow usage of dark grey listed APIs. 223 | * よく使うのは 1 or 2あたりかなー 224 | 225 | 226 | ## How can I enable access to non-SDK APIs? 227 | 228 | * 動作確認終わったら設定した値は消しましょ 229 | 230 | ``` 231 | adb shell settings delete global hidden_api_policy_pre_p_apps 232 | adb shell settings delete global hidden_api_policy_p_apps 233 | ``` 234 | 235 | ## どうやってアプリでnon-SDKを使ってるのを調べるか 236 | 237 | * StrictMode + Logcat 238 | * static analysis tool `veridex` 239 | 240 | 241 | ## StrictMode + Logcat 242 | 243 | * StrictMode.VmPolicy.Builder#detectNonSdkApiUsageをStrictModeのsetVmPolicyに設定する 244 | * https://developer.android.com/reference/android/os/StrictMode.VmPolicy.Builder.html#detectNonSdkApiUsage() 245 | 246 | ```kotlin 247 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 248 | StrictMode.setVmPolicy( 249 | StrictMode.VmPolicy 250 | .Builder() 251 | .detectNonSdkApiUsage() 252 | .build()) 253 | } 254 | ``` 255 | 256 | ## StrictMode + Logcat 257 | 258 | * StrictModeを設定したアプリがnon-SDKにアクセスするとLogcatにログが出る 259 | * どのメソッドやフィールドなのかと、どのlistに属するものなのかが出て便利 260 | 261 | ```java 262 | Accessing hidden method Landroid/gesture/Gesture;->setID(J)V (blacklist, reflection) 263 | ``` 264 | 265 | ## StrictMode + Logcat 266 | 267 | * StackTraceも表示される 268 | 269 | ```java 270 | D/StrictMode(19092): StrictMode policy violation: android.os.strictmode.NonSdkApiUsedViolation: Landroid/widget/Toast;->mDuration:I 271 | D/StrictMode(19092): at android.os.StrictMode.lambda$static$1(StrictMode.java:428) 272 | D/StrictMode(19092): at android.os.-$$Lambda$StrictMode$lu9ekkHJ2HMz0jd3F8K8MnhenxQ.accept(Unknown Source:2) 273 | D/StrictMode(19092): at java.lang.Class.getDeclaredField(Native Method) 274 | D/StrictMode(19092): at com.os.operando.non_sdkinterfaces.sample.MainActivity$onCreate$3.onClick(MainActivity.kt:49) 275 | D/StrictMode(19092): at android.view.View.performClick(View.java:6597) 276 | D/StrictMode(19092): at android.view.View.performClickInternal(View.java:6574) 277 | D/StrictMode(19092): at android.view.View.access$3100(View.java:778) 278 | D/StrictMode(19092): at android.view.View$PerformClick.run(View.java:25883) 279 | D/StrictMode(19092): at android.os.Handler.handleCallback(Handler.java:873) 280 | D/StrictMode(19092): at android.os.Handler.dispatchMessage(Handler.java:99) 281 | D/StrictMode(19092): at android.os.Looper.loop(Looper.java:193) 282 | D/StrictMode(19092): at android.app.ActivityThread.main(ActivityThread.java:6642) 283 | D/StrictMode(19092): at java.lang.reflect.Method.invoke(Native Method) 284 | D/StrictMode(19092): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 285 | D/StrictMode(19092): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 286 | ``` 287 | 288 | ## static analysis tool `veridex` 289 | 290 | * StrictModeだと実行しないとわからない 291 | * そこで`veridex`を使う 292 | * apkを解析して、使用してるnon-SDKを
表示してくれる 293 | 294 | ## static analysis tool `veridex` 295 | 296 | * appcompatのディレクトリごとtgzでダウンロードする 297 | * 以下にアクセスして、ダウンロードできる 298 | * https://android.googlesource.com/platform/prebuilts/runtime/+/master/appcompat/ 299 | 300 | ![](images/osu.png) 301 | 302 | ## static analysis tool `veridex` 303 | 304 | * ダウンロードしたらPCのOSごとのzipを解凍 305 | * あとは解析したいapkをshell scriptに指定 306 | 307 | ```bash 308 | ./appcompat.sh --dex-file=test.apk 309 | ``` 310 | 311 | ## veridex - output 312 | 313 | ![](images/result-1.png) 314 | ![](images/result-2.png) 315 | 316 | ## veridex - output 317 | 318 | ![](images/result-3.png) 319 | 320 | 321 | ## static analysis tool `veridex` 322 | 323 | * 便利 324 | * どこでnon-SDKを参照してるのかも出る 325 | * もちろんライブラリ側でnon-SDK参照してるところもわかる 326 | * まずは一度apkをぶっこんでみるのおすすめ 327 | 328 | 329 | ## non-SDK FAQ 330 | 331 | * FAQがドキュメントにしっかり書いてあるので、詳しく読むと良さげ 332 | * https://developer.android.com/preview/restrictions-non-sdk-interfaces#faq 333 | 334 | 335 | ## Are the blacklist / greylists the same on different OEM devices with the same Android versions? 336 | 337 | * Yes OEMs can add their own apis to the blacklist, but cannot remove things from the original/AOSP black or grey lists. The CDD prevents such changes and CTS tests ensure that the Android Runtime is enforcing the list. 338 | 339 | 340 | ## 今後の開発で意識したいこと 341 | 342 | * できるだけAndroid FrameworkのSDKはリフレクションしない 343 | * 元々しないように気をつけた方が良かったけど、今後はさらに 344 | * non-SDKを使うならどのlistに属するか調べる 345 | 346 | 347 | ## 思ったことなどなど 348 | 349 | * non-SDKを使ってる場合にGoogle Play Consoleとかにも出してほしいかも 350 | * release buildでも出してほしいかもなー 351 | * non-SDKの各リストの内容の更新はOSアップデートのタイミングとかでされる? 352 | * パッチレベルでは更新なさそう 353 | * あるとすればOSバージョンアップくらいのアップデートの時かもね 354 | * 使用してるライブラリがnon-SDKを使っていたらissueやPRを出そう 355 | * Contribute chance 356 | 357 | 358 | ## まとめ 359 | 360 | * あきらめて踊る前にがんばろう 361 | 362 | 363 | ## 参考資料 364 | 365 | * Restrictions on non-SDK interfaces 366 | * https://developer.android.com/preview/restrictions-non-sdk-interfaces 367 | * Improving Stability by Reducing Usage of non-SDK Interfaces 368 | * https://android-developers.googleblog.com/2018/02/improving-stability-by-reducing-usage.html 369 | * An Update on non-SDK restrictions in Android P 370 | * https://android-developers.googleblog.com/2018/06/an-update-on-non-sdk-restrictions-in.html 371 | 372 | 373 | ## Thanks!! -------------------------------------------------------------------------------- /potatotips_52/images/non-sdk-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/potatotips_52/images/non-sdk-list.png -------------------------------------------------------------------------------- /potatotips_52/images/non-sdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/potatotips_52/images/non-sdk.png -------------------------------------------------------------------------------- /potatotips_52/images/okhttp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/potatotips_52/images/okhttp.png -------------------------------------------------------------------------------- /potatotips_52/images/osu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/potatotips_52/images/osu.png -------------------------------------------------------------------------------- /potatotips_52/images/result-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/potatotips_52/images/result-1.png -------------------------------------------------------------------------------- /potatotips_52/images/result-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/potatotips_52/images/result-2.png -------------------------------------------------------------------------------- /potatotips_52/images/result-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/potatotips_52/images/result-3.png -------------------------------------------------------------------------------- /retty_tech_cafe_6/README.md: -------------------------------------------------------------------------------- 1 | ## Inside Android N 2 | 3 | * Retty Tech Cafe#6 4 | 5 | 6 | ## Android N Developer Preview 5 7 | 8 | * Developer Preview 5 includes near-final system images 9 | 10 | 11 | ## API Diff 12 | 13 | ## API Diff 14 | 15 | * API Differences between 23 and 24 16 | * https://developer.android.com/sdk/api_diff/24/changes.html 17 | * https://developer.android.com/sdk/api_diff/24/changes/jdiff_statistics.html 18 | 19 | ## Good-bye android.test package 20 | 21 | ## Good-bye android.test package 22 | 23 | * Deprecated in API level 24 24 | 25 | ## Good-bye android.test package 26 | 27 | * 😡 28 | 29 | ## Good-bye android.test package 30 | 31 | * https://developer.android.com/sdk/api_diff/24/changes/pkg_android.test.html 32 | * https://developer.android.com/sdk/api_diff/24/changes/pkg_android.test.mock.html 33 | * https://developer.android.com/sdk/api_diff/24/changes/pkg_android.test.suitebuilder.annotation.html 34 | 35 | 36 | ## Good-bye android.test package🔥🔥🔥 37 | 38 | * 生き残りは少しだけいる😊 39 | * Android Testing Support Libraryにしろって話 40 | * https://developer.android.com/topic/libraries/testing-support-library/index.html 41 | * ちなみ僕は最近MockCursor使ってテストコード書きました😢 42 | * MockCursorはDeprecatedでーす🔥🔥🔥🔥🔥🔥🔥🔥🔥 43 | 44 | ## android.provider 45 | 46 | ## android.provider.Settings.Global.BOOT_COUNT 47 | 48 | * Settings.Global.BOOT_COUNT 49 | * 起動した回数を取得できる 50 | * うん、で?? なAPI 51 | * https://developer.android.com/reference/android/provider/Settings.Global.html#BOOT_COUNT 52 | 53 | 54 | ## android.provider.Settings.ACTION_WEBVIEW_SETTINGS 55 | 56 | * Settings.ACTION_WEBVIEW_SETTINGS 57 | * Allows user to select current webview implementation. 58 | * 例えばChrome Stable,Beta,Devが入ってた場合、実装を選べるってことみたい 59 | * https://developer.android.com/reference/android/provider/Settings.html#ACTION_WEBVIEW_SETTINGS 60 | 61 | 62 | ## android.text.Html 63 | 64 | * Html.toHtml method deprecated 65 | * Html.fromHtml method deprecated 66 | * https://developer.android.com/sdk/api_diff/24/changes/android.text.Html.html 67 | * optionを引数で追加したメソッド使えってことらしい 68 | 69 | 70 | ## Key Developer Features 71 | 72 | ## Data Saver 73 | 74 | * システムがバックグラウンドで行われる通信をブロックする 75 | * フォアグラウンドでのデー使用をなるべく抑える 76 | * 特定のアプリだけホワイトリストに入れて通信のブロックをさせないこともできる 77 | * https://developer.android.com/preview/features/data-saver.html 78 | 79 | ## Data Saver 80 | 81 | * Data Saverの設定取得・変更監視できる 82 | * ホワイトリストへの追加を要求できる 83 | * 実装簡単だった 84 | * フォアグラウンドでのデータ使用量はなんかドキュメント読んだ感じ開発者に任せます的な勢いだった 85 | * 要はData SaverがONかどうか確認して、ONならデータ使用量を抑える 努力 をしてね💪 86 | * おい、開発者の善意に委ねられるってことか... 87 | 88 | 89 | ## Data Saver Sample 90 | 91 | * https://github.com/operando/Data-Saver-Sample 92 | 93 | 94 | ## さて、つついてみるか 95 | 96 | * Data Saver設定画面にIntentで飛べるか?? 97 | * 今のところの情報じゃ無理っぽい 98 | * SettingsのActionはもちろん提供されてない 99 | * 画面がFragmentだし無理そう 100 | * com.android.settings.datausage.DataSaverSummary 101 | * Data Saverのホワイトリストがどこで管理されているのか 102 | * netpolicy.xmlかなー多分 103 | * エミュレーターでもshellで入っても全然Fileが見れないので厳しい... 104 | 105 | 106 | ## SQLite 107 | 108 | 109 | ## SQLite 110 | 111 | * Android Nに入ってるSQLiteのversionを調べてみた 112 | * 実は部分的にAOSPのコミットが公開されている 113 | 114 | 115 | ## AOSP changelog 116 | 117 | * http://www.androidpolice.com/android_aosp_changelogs/android-m-preview-2-to-android-n-preview-1-AOSP-changelog.html 118 | * http://www.androidpolice.com/android_aosp_changelogs/android-n-preview-1-to-android-n-preview-2-AOSP-changelog.html 119 | * http://www.androidpolice.com/android_aosp_changelogs/android-n-preview-2-to-android-n-preview-3-AOSP-changelog.html 120 | * http://www.androidpolice.com/android_aosp_changelogs/android-n-preview-3-to-android-n-preview-4-AOSP-changelog.html 121 | 122 | 123 | ## SQLite 124 | 125 | * 調べてみた感じ SQLite 3.9.3 みたい 126 | * コミット 127 | * https://android.googlesource.com/platform/external/sqlite/+/253ed64ded244ef3d8a7226efb812e7989bc8026 128 | 129 | 130 | ## SQLite 3.9.x 131 | 132 | * json1 extension 133 | * Full Text Search version 5 (FTS5) 134 | * etc. 135 | 136 | ## SQLite 3.9.x 137 | 138 | * 残念です... 139 | 140 | ## SQLite 3.9.x 141 | 142 | * 今紹介した機能はAndroidのSQLiteでは使えません 143 | 144 | ## SQLite 3.9.x 145 | 146 | * \(^o^)/ 147 | 148 | 149 | ## Why? 150 | 151 | * それぞれの機能を使うためにflagをenableにしないといけない 152 | * なるほど...されてない... 153 | * https://android.googlesource.com/platform/external/sqlite/+/master/dist/Android.mk#9 154 | 155 | 156 | ## ワンチャン俺の見間違えだろ... 157 | 158 | * Android NのSQLiteでJSON1 Extension試してみた 159 | * https://github.com/operando/Try-Android-N-The-JSON1-Extension 160 | 161 | ## 結果 162 | 163 | * \(^o^)/ 164 | 165 | ## JSON1 Extensionを有効にしたSQLiteをbuildする 166 | 167 | * JSON1 Extensionを有効にしたSQLiteをbuildする 168 | * Not Android!! 169 | * http://qiita.com/operandoOS/items/4dc7754a23ad5ab58615 170 | 171 | ## EasterEgg 172 | 173 | * ねこあつめ homage EasterEgg🐱 174 | 175 | ## 🐱 176 | 177 | * 🐱 178 | 179 | ## Android N EasterEgg Neko Atsume Launcher 180 | 181 | * Setting Tile長押しだるい🐱 182 | * はやくねこ見たい🐱🐱 183 | 184 | ## Android N EasterEgg Neko Atsume Launcher 185 | 186 | * https://github.com/operando/Neko-Atsume-Launcher 187 | 188 | 189 | ## Reddit ANA(Ask us Anything) 190 | 191 | * We’re on the Android engineering team and built Android Nougat. Ask us Anything! 192 | * https://www.reddit.com/r/androiddev/comments/4tm8i6/were_on_the_android_engineering_team_and_built/ 193 | * 終わってるけど... 194 | 195 | ## 気になったPost 196 | 197 | * API 24 brought partial introduction of Java 8 types and methods. There are highly noticeable omissions from this addition such as java.time.* (JSR 310), java.lang.invoke.*, and convenience methods on String (like join). There also continues to be an absence of types and methods from Java 7 like java.nio.path.*. 198 | As Android's standard library deviates further from properly mirroring the JDK, what are the views of the platform team with regard to these omissions? Are you concerned about the growing difficulty of the use and development of non-Android-specific libraries moving forward (whether they're pure-Java or want to target both the JVM and Android)? 199 | * https://www.reddit.com/r/androiddev/comments/4tm8i6/were_on_the_android_engineering_team_and_built/d5ieg6r 200 | 201 | ## 回答 202 | 203 | * Anwar: We plan to support more of the Java 8 programming language spec in future releases. We have to prioritize what we spend our time on as we often have to optimize these implementations quite a bit for mobile, so these sometime roll out over multiple releases. In general, we’re shortening the lag between platform support for new language spec. 204 | -------------------------------------------------------------------------------- /schoo_2015_10_29/README.md: -------------------------------------------------------------------------------- 1 | 2 | # schoo 資料もろもろ 3 | 4 | * 主に資料内で紹介しているもののリンク集 5 | * 一部、資料内に書ききれなかったものあり 6 | 7 | # スライド 8 | 9 | * [はじめる前に知っておきたいAndroidアプリ開発のポイント](http://www.slideshare.net/shinobuokano7/android-54556612) 10 | * http://www.slideshare.net/shinobuokano7/android-54556612 11 | 12 | # Keynote Template 13 | 14 | * [更に大体いい感じになるkeynoteテンプレート「Azusa Colors」作った](http://memo.sanographix.net/post/113681262780) 15 | 16 | # Convert markdown to keynote 17 | 18 | * [md2key](https://github.com/k0kubun/c) 19 | 20 | 21 | # [はじめる前に知っておきたいAndroidアプリ開発のポイント](https://schoo.jp/class/2898) 22 | 23 | 24 | # 2. 自己紹介 25 | 26 | * 岡野 忍 ([@operandoOS](https://twitter.com/operandoOS)) 27 | * 株式会社メルカリ 28 | * Androidのコードを読む勉強会を運営 29 | * [まったりAndroid Framework Code Reading](https://mandroidfcr.doorkeeper.jp/) 30 | 31 | 32 | ## 8. Androidのバージョン別シェア率 33 | 34 | * [Dashboards](https://developer.android.com/about/dashboards/index.html) 35 | * シェア率等が月一で更新される 36 | * https://developer.android.com/about/dashboards/index.html 37 | 38 | 39 | ## 10. Android Studio 40 | 41 | * [Android Studio最速入門~効率的にコーディングするための使い方](http://gihyo.jp/dev/serial/01/android_studio) 42 | 43 | 44 | ## 12. アプリをどこで動かすか 45 | 46 | * [Genymotion](https://www.genymotion.com/) 47 | 48 | 49 | ## 20. 入門書で学ぶ 50 | 51 | * [Android学ぶ上での書籍について](http://hack-it-iron.hatenablog.com/entry/2015/03/22/195939) 52 | 53 | 54 | ## 23. サンプルコード等で学ぶ 55 | 56 | * [Android Training](http://developer.android.com/training/index.html) 57 | * [API Guides](http://developer.android.com/guide/index.html) 58 | * [Samples](https://developer.android.com/samples/index.html) 59 | * [Github - Google Samples](https://github.com/googlesamples?utf8=%E2%9C%93&query=android) 60 | 61 | ## 25. サンプルコード等で学ぶ 62 | 63 | * [mixi-inc/AndroidTraining](https://github.com/mixi-inc/AndroidTraining) 64 | 65 | 66 | ## 26. 日々どこから情報を仕入れているか 67 | 68 | * [Qiita tags Android](http://qiita.com/tags/android) 69 | * [Android Developers Blog](http://android-developers.blogspot.jp/) 70 | * [Android Weekly](http://androidweekly.net/#latest-issue) 71 | * [Android Developers Backstage](http://androidbackstage.blogspot.jp/) 72 | * [Fragmented](http://fragmentedpodcast.com/) 73 | 74 | 75 | ## 27. Androidをより深く学ぶために 76 | 77 | * [Android セキュアコーディングガイド](https://www.jssec.org/report/securecoding.html) 78 | * [The Android Arsenal](https://android-arsenal.com/) 79 | * OS標準の開発者オプション 80 | * [Android 5.0 Lollipopの開発者オプション詳細解説](http://techbooster.org/android/environment/16955/) 81 | * Github上で公開されているアプリのソースコード 82 | * [iosched](https://github.com/google/iosched) 83 | * [santa-tracker-android](https://github.com/google/santa-tracker-android) 84 | * [Rebuild](https://github.com/rejasupotaro/Rebuild) 85 | * [WordPress-Android](https://github.com/wordpress-mobile/WordPress-Android) 86 | * [wordpress-mobile](https://github.com/wordpress-mobile) 87 | 88 | ## 34. 開発 89 | 90 | * [DeployGate](https://deploygate.com/?locale=ja) 91 | 92 | 93 | ## 37. リリース 94 | 95 | * [アルファ版またはベータ版テストと段階的公開の使用](https://support.google.com/googleplay/android-developer/answer/3131213) 96 | * [アプリのアップロードと販売または配布 > 標準公開または時限公開を使用したアプリの更新](https://support.google.com/googleplay/android-developer/answer/113469?rd=1#modes) 97 | * [Google Play Developer Consoleの時限公開機能を試してみた](http://qiita.com/konifar/items/4f8da43e98c573ceb7c4) 98 | * [tonkotsu](https://github.com/operando/tonkotsu) 99 | 100 | 101 | ## 39. 分析 102 | 103 | * [Crashlytics](https://try.crashlytics.com/) 104 | 105 | 106 | ## 42. Material Design 107 | 108 | * [Material Design Top](https://design.google.com/) 109 | * [Material Design Introduction](https://www.google.com/design/spec/material-design/introduction.html) 110 | 111 | 112 | ## 44. Material Design 113 | 114 | * [Material Design 時代の最新アプリ UI/UX デザイン
 〜 マルチデバイス対応とウェアラブル体験のために](https://www.youtube.com/watch?v=xKrtTlCvB-Q&feature=youtu.be&t=3h59m34s) 115 | 116 | 117 | ## 46. Material icons 118 | 119 | * [Material icons](https://www.google.com/design/icons/) 120 | 121 | 122 | ## 47. Material Design - Sample 123 | 124 | * [Topeka for Android](https://github.com/googlesamples/android-topeka) 125 | 126 | 127 | ## 49. Android開発者の
カンファレンスに参加する 128 | 129 | * [shibuya.apk](http://shibuya-apk.connpass.com/) 130 | * [Roppongi.aar](http://roppongi-aar.connpass.com/) 131 | * [potatotips](potatotips) 132 | 133 | 134 | ## 50. Android開発者の
カンファレンス - 日本 135 | 136 | * [Android Bazaar & Conference Diverse 2015 Kanazawa](http://connpass.com/event/21874/) 137 | * [DroidKaigi 2015](https://droidkaigi.github.io/2015/) 138 | * [DroidKaigi 2016](https://droidkaigi.github.io/2016/) 139 | 140 | 141 | ## 51. Android開発者の
カンファレンス - Global 142 | 143 | * [Droidcon](http://droidcon.com/) 144 | * [Google IO](https://events.google.com/io2015/) 145 | 146 | 147 | ## 52. Android 6.0 / M(Marshmallow) 148 | 149 | * [Android 6.0 APIs](http://developer.android.com/intl/ja/about/versions/marshmallow/android-6.0.html) 150 | * [Android 6.0 Changes](http://developer.android.com/intl/ja/about/versions/marshmallow/android-6.0-changes.html) 151 | * [Android 6.0 Samples](http://developer.android.com/intl/ja/about/versions/marshmallow/samples.html) 152 | 153 | 154 | ## 53. Runtime Permissions 155 | 156 | * [Runtime Permissions](http://developer.android.com/intl/ja/training/permissions/index.html) 157 | 158 | 159 | ## 57. 告知 160 | 161 | * [メルカリはAndroidエンジニア積極採用中です!](https://www.wantedly.com/projects/11969) 162 | 163 | 164 | # おまけ 165 | 166 | ## Android OS / ソースコード 167 | 168 | * [Androidソースコード検索サービス](https://sites.google.com/site/devcollaboration/codesearch) 169 | * Android OSそのもののソースコードが見れるサイト。 170 | * 内部構造を知る場合にとても便利。 171 | 172 | * [Android Open Source Project](https://source.android.com/index.html) 173 | * Android OSの仕様をドキュメントにまとめているもの。 174 | * その他、内部構造を理解するための情報が詰まってる 175 | 176 | ## Google Play Services 177 | 178 | * https://developers.google.com/android/ 179 | 180 | 181 | ## Gradle 182 | 183 | * http://gradle.org/ 184 | * http://google.github.io/android-gradle-dsl/ 185 | * http://google.github.io/android-gradle-dsl/current/ 186 | * http://mixi-inc.github.io/AndroidTraining/introductions/1.05.how-to-build-for-gradle.html 187 | * https://gradle.org/getting-started-android/ 188 | * http://wasabeef.jp/android-gradle/ 189 | * http://tools.android.com/tech-docs/new-build-system/user-guide 190 | 191 | 192 | ## Google Play アプリ ポリシー センター 193 | 194 | * https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja 195 | 196 | 197 | ## Core App Quality 198 | 199 | * http://developer.android.com/distribute/essentials/quality/core.html 200 | 201 | 202 | ## Essentials for a Successful App 203 | 204 | * http://developer.android.com/distribute/essentials/index.html 205 | -------------------------------------------------------------------------------- /schoo_2015_10_29/links.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 8. Androidのバージョン別シェア率 4 | 5 | * Dashboards 6 | * https://developer.android.com/about/dashboards/index.html 7 | 8 | 9 | ## 10. Android Studio 10 | 11 | * Android Studio最速入門~効率的にコーディングするための使い方 12 | * http://gihyo.jp/dev/serial/01/android_studio 13 | 14 | 15 | ## 12. アプリをどこで動かすか 16 | 17 | * Genymotion 18 | * https://www.genymotion.com/ 19 | 20 | 21 | ## 20. 入門書で学ぶ 22 | 23 | * Android学ぶ上での書籍について 24 | * http://hack-it-iron.hatenablog.com/entry/2015/03/22/195939 25 | 26 | 27 | ## 23. サンプルコード等で学ぶ 28 | 29 | * Android Training 30 | * http://developer.android.com/training/index.html 31 | 32 | 33 | * API Guides 34 | * http://developer.android.com/guide/index.html 35 | 36 | 37 | * Samples 38 | * https://developer.android.com/samples/index.html 39 | 40 | 41 | * Github - Google Samples 42 | * https://github.com/googlesamples?utf8=%E2%9C%93&query=android 43 | 44 | 45 | ## 25. サンプルコード等で学ぶ 46 | 47 | * mixi-inc/AndroidTraining 48 | * https://github.com/mixi-inc/AndroidTraining 49 | 50 | 51 | ## 26. 日々どこから情報を仕入れているか 52 | 53 | * Qiita tags Android 54 | * http://qiita.com/tags/android 55 | 56 | * Android Developers Blog 57 | * http://android-developers.blogspot.jp/ 58 | 59 | * Android Weekly 60 | * http://androidweekly.net/#latest-issue 61 | 62 | * Android Developers Backstage 63 | * http://androidbackstage.blogspot.jp/ 64 | 65 | * Fragmented 66 | * http://fragmentedpodcast.com/ 67 | 68 | 69 | ## 27. Androidをより深く学ぶために 70 | 71 | * Android セキュアコーディングガイド 72 | * https://www.jssec.org/report/securecoding.html 73 | 74 | * The Android Arsenal 75 | * https://android-arsenal.com/ 76 | 77 | 78 | ## 34. 開発 79 | 80 | * DeployGate 81 | * https://deploygate.com/?locale=ja 82 | 83 | 84 | ## 37. リリース 85 | 86 | * アルファ版またはベータ版テストと段階的公開の使用 87 | * https://support.google.com/googleplay/android-developer/answer/3131213 88 | 89 | * アプリのアップロードと販売または配布 > 標準公開または時限公開を使用したアプリの更新 90 | * https://support.google.com/googleplay/android-developer/answer/113469?rd=1#modes 91 | 92 | * Google Play Developer Consoleの時限公開機能を試してみた 93 | * http://qiita.com/konifar/items/4f8da43e98c573ceb7c4 94 | 95 | * tonkotsu 96 | * https://github.com/operando/tonkotsu 97 | 98 | 99 | ## 39. 分析 100 | 101 | * Crashlytics 102 | * https://try.crashlytics.com/ 103 | 104 | 105 | ## 42. Material Design 106 | 107 | * Material Design 108 | * https://design.google.com/ 109 | 110 | 111 | ## 44. Material Design 112 | 113 | * Material Design 時代の最新アプリ UI/UX デザイン
 〜 マルチデバイス対応とウェアラブル体験のために 114 | * https://www.youtube.com/watch?v=xKrtTlCvB-Q&feature=youtu.be&t=3h59m34s 115 | 116 | 117 | ## 46. Material icons 118 | 119 | * Material icons 120 | * https://www.google.com/design/icons/ 121 | 122 | 123 | ## 47. Material Design - Sample 124 | 125 | * Topeka for Android 126 | * https://github.com/googlesamples/android-topeka 127 | 128 | ## 52. Android 6.0 / M(Marshmallow) 129 | 130 | * Android 6.0 / M(Marshmallow) 131 | * http://developer.android.com/intl/ja/about/versions/marshmallow/android-6.0.html 132 | 133 | 134 | ## 53. Runtime Permissions 135 | 136 | * Runtime Permissions 137 | * http://developer.android.com/intl/ja/training/permissions/index.html 138 | 139 | 140 | ## 57. 告知 141 | 142 | * メルカリはAndroidエンジニア積極採用中です! 143 | * https://www.wantedly.com/projects/11969 144 | -------------------------------------------------------------------------------- /まったりAndroid Framework Code Reading_2/README.md: -------------------------------------------------------------------------------- 1 | # [まったりAndroid Framework Code Reading #2](https://mandroidfcr.doorkeeper.jp/events/33925) 2 | 3 | # 会場説明 + 諸注意 4 | 5 | * Wi-Fiあります 6 | * 飲食可です(お菓子用意しました。食べてね★) 7 | * お手洗いありますが、会場出入りのセキュリティ上
責任者の付き添いが必要なので 釘宮さんに一声
かけてください 8 | * 途中でお帰りになる際には、私に一声かけてください 9 | 10 | # タイムテーブル 11 | 12 | 13 | # まったりAndroid Framework Code Reading?? 14 | 15 | * とある一人のAndroidエンジニアが始めた誰得勉強会です 16 | 17 | 18 | # About Me 19 | 20 | * Shinobu Okano(@operandoOS) 21 | * Mercari, Inc. 22 | * Logcat大好きでーす!!! 23 | 24 | 25 | # Code Readingの目的 26 | 27 | * Androidのソースコードを読んで開発等に役立てる 28 | 29 | 30 | # Code Readingの目的 31 | 32 | * カジュアルにまったり色んなコードを読んで成果や知識を共有できれば最高 33 | 34 | 35 | # Android Frameworkとは?? 36 | 37 | * アプリ開発者がカジュアルに読めるのはここらへん 38 | 39 | 40 | # Code Reading Q&A 41 | 42 | * Q. SDKのコードでもOK?? 43 | * A. もちろんOK! 44 | * Q. ライブラリのコードでもOK?? 45 | * もちろんOK! 46 | * Q. HALやKernel、ARTでもOK?? 47 | * A. 大歓迎! 48 | 49 | 50 | # Code Readingの成果 51 | 52 | * Github Organizationにまとめていく 53 | * https://github.com/AndroidFrameworkCodeReading 54 | * ※きちんとした成果を強制するわけじゃありません 55 | * ざっくりの成果でOK(Markdownでざっくりとか) 56 | 57 | 58 | # 勉強会でのやりとりなどなど… 59 | 60 | * Gitter用意してます!(誰でも参加できます) 61 | * 残しておきたいやりとり 62 | * 気になったこと 63 | * 成果 / 共有したいこと 64 | * などなど… 65 | * オープンな活動のためGitterご利用ください! 66 | * https://gitter.im/AndroidFrameworkCodeReading/CodeReadingHistory 67 | 68 | 69 | # まったりAndroid Framework Code Reading 70 | 71 | * 「もっと詳しく!」はこちらを読んでください! 72 | * ポエムです 73 | * http://hack-it-iron.hatenablog.com/entry/2015/06/11/143629 74 | 75 | 76 | # まったりAndroid Framework Code Reading #2 77 | 78 | * 裏テーマ 79 | * Android M 読もう! 80 | 81 | 82 | # Android M 83 | 84 | * Permission 85 | * Doze 86 | * Direct Share 87 | * App Links 88 | * Material Design Support Library 89 | * Data Binding 90 | * etc… 91 | 92 | # OpenGrok - Android M 93 | 94 | # なに読もうかなー 95 | 96 | * なにを読むのか決めてくださーい! 97 | * ざっくりでOK 98 | * 誰かと相談したり、一緒に読んだりでもOK 99 | 100 | 101 | # なに読もうかなー 102 | 103 | * 例えば 104 | * Intentの仕組みを知りたい! 105 | * Storageの仕組みを知りたい! 106 | * Mediaの仕組みを知りたい! 107 | * とにかくAndroidを壊したい! 108 | * とかとか… 109 | 110 | 111 | # Enjoy Code Reading!! -------------------------------------------------------------------------------- /まったりAndroid Framework Code Reading_2/note.md: -------------------------------------------------------------------------------- 1 | 2 | # 用意するもの 3 | 4 | * お好みのEditor 5 | * OpenGrok 6 | * https://sites.google.com/site/devcollaboration/codesearch 7 | * 基本これだけ 8 | 9 | 10 | # 読みやすい環境を作る 11 | 12 | * Firefoxのツリー型タブという拡張がオススメ 13 | * https://addons.mozilla.org/ja/firefox/addon/tree-style-tab/ 14 | * 読んでいるコードのメソッド呼び出しの階層とか管理しやすい 15 | 16 | 17 | # 手元にコードをダウンロードする 18 | 19 | * 全部のソースコードをダウンロードするのは大変 20 | * OpenGrokからFile単位でダウンロードできる 21 | * よく参照するファイルはダウンロードしておくと便利 22 | * URLのxrefとrawにしてアクセスするとBrowser経由でダウンロードできるはず 23 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/Activity.java 24 | * http://tools.oesf.biz/android-6.0.0_r1.0/raw/frameworks/base/core/java/android/app/Activity.java 25 | 26 | 27 | # OpenGrokに慣れる 28 | 29 | * Full Searchを指定する 30 | * File Pathを指定する 31 | * 基本上2つでだいたいOK 32 | * 困ったらHelpを見て使い方をマスターする 33 | * http://tools.oesf.biz/android-6.0.0_r1.0/help.jsp 34 | 35 | 36 | # 意外と手元に持っているソースコード 37 | 38 | * Android SDK Managerから取得できるもの 39 | * /Applications/Android Studio.app/sdk/sources 40 | * /Applications/Android Studio.app/sdk/extras/android/support 41 | * /Applications/Android Studio.app/sdk/extras/android/m2repository/com/android/support 42 | 43 | # 44 | 45 | * frameworks/ 46 | * frameworks/base/core/java/ 47 | * packages/apps/ 48 | * http://tools.oesf.biz/android-6.0.0_r1.0/xref/packages/apps/Settings/ 49 | 50 | # その他 51 | 52 | * https://source.android.com/index.html 53 | * https://github.com/android -------------------------------------------------------------------------------- /俺的 2017年のAndroidを振り返る/README.md: -------------------------------------------------------------------------------- 1 | # 俺的 2017年のAndroidを振り返る 2 | 3 | ## ハッシュタグ 4 | 5 | * [#opedroid](https://twitter.com/search?f=tweets&q=%23opedroid) 6 | 7 | ## 自己紹介 8 | 9 | * operandoOS 10 | * Androidのアプリを作ってます 11 | 12 | 13 | ## なぜ発表を配信するのか? 14 | 15 | * より多くの人に発表を
見て・聞いてもらうため 16 | 17 | 18 | ## なぜ発表を配信するのか? 19 | 20 | * IT業界では各地で日々勉強会が開かれており
色んな人が自身の知見を発表しています 21 | * 私も発表してる一人です 22 | 23 | 24 | ## なぜ発表を配信するのか? 25 | 26 | * 発表するはいいけど、資料作りが大変だったり、資料に
書かれなかったことを発表の場で話したりします 27 | * なので、資料に書かず話してしまうと後々公開される資料を見ても、どんなことを話したのかわかりづらい場合があります 28 | * もちろん資料をちゃんと作っている方のは、資料だけでも理解できます 29 | * しかし、私は資料作るのが下手くそです 30 | 31 | 32 | ## なぜ発表を配信するのか? 33 | 34 | * でも、知見は誰かのためになるかもしれないので共有したいのです! 35 | * なので、資料はざっくり作って、後は話してしまって、それを録画なりして公開すればええんでないかと思いました 36 | * 大きなカンファレンスとかでは、実際に発表の録画が公開されることもあります 37 | 38 | 39 | ## 詳しく 40 | 41 | * より多くの人に発表をみて・きいてもらうために 42 | * https://note.mu/operando_os/n/n0ff7064fbc03 43 | 44 | 45 | ## 意見、要望、質問など 46 | 47 | * Twitterのハッシュタグに書いていただければ
嬉しいです 48 | * [#opedroid](https://twitter.com/search?f=tweets&q=%23opedroid) 49 | 50 | 51 | ## 2017年 ざっくりAndroid全体で起きたこと振り返り 52 | 53 | * ※書いてあること、話したことがすべてではないです 54 | * 
※個人的に印象に残ってることだけ書いてます 55 | 56 | 57 | ### Android Announces Support for Kotlin 58 | 59 | * https://android-developers.googleblog.com/2017/05/android-announces-support-for-kotlin.html 60 | * Kotlin 61 | * https://kotlinlang.org/ 62 | * KotlinConf 2017 63 | * https://www.kotlinconf.com/ 64 | 65 | 66 | ### Android O 67 | 68 | * https://developer.android.com/about/versions/oreo/index.html 69 | * 来年はO対応必須っぽい流れになってるので頑張ろうな! 70 | * Push通知めっちゃ運用してるアプリはNotification Channel大変だからな! 71 | * それ以外はアプリによって対応難しいのはまちまち 72 | 73 | 74 | ### Improving app security and performance on Google Play for years to come 75 | 76 | * https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html 77 | * アプリのセキュリティとパフォーマンス向上を目指したい 78 | * target API level上げて対応しないアプリはいくつか問題あるって話 79 | * パーミッション取り放題、バックグラウンドで通信したい放題 etc. 80 | * ユーザの体験も悪い 81 | * だからtarget API level最新にしてね!とか64bit対応してね!って感じ 82 | 83 | 84 | ### Target API level requirement from late 2018 85 | 86 | * 以下のスケジュールで要求するtarget API level以上にしないとダメだからって話 87 | * 2018年8月 新規でリリースするアプリはtarget API leve 26(Android 8.0)以上をターゲットにする 88 | * 2018年11月 既存のアプリのアップデートにはtarget API leve26以上をターゲットにする 89 | * 2019年以降 毎年targetSdkVersion上げていこうな! 90 | 91 | ### Target API level requirement from late 2018 92 | 93 | * 既存のアプリでもうリリースする予定がないアプリは影響ないよ 94 | * minSdkVersionじゃないから誤解しないでね! 95 | * targetSdkVersionだからね! 96 | 97 | 98 | ### 64-bit support requirement in 2019 99 | 100 | * 詳しくないので割愛 101 | * Native Libraryを含まないアプリは影響ない 102 | * とはいえ、いつNative Library使うかわからんので頭の片隅に入れておく方がいい 103 | 104 | 105 | ### Android Studio 3.0 106 | 107 | * 色々便利になったね! 108 | * https://android-developers.googleblog.com/2017/10/android-studio-30.html 109 | * まだちゃんと全部使いこなせてない... 110 | 111 | 112 | ### Support Library 113 | 114 | * 26から minimum SDK versionが14になったね 115 | * Recent Support Library Revisions 116 | * https://developer.android.com/topic/libraries/support-library/revisions.html 117 | 118 | 119 | ### Google Play services 120 | 121 | * 10.2から minimum SDK versionが14になったね 122 | * Release Notes 123 | * https://developers.google.com/android/guides/releases 124 | * 2系対応お疲れ様でしたの年っぽい 125 | 126 | 127 | ### Android Architecture Components 128 | 129 | * 来年も盛り上がりそう 130 | * 日々改善されてもっといいLibraryになりそう 131 | * https://developer.android.com/topic/libraries/architecture/index.html 132 | 133 | 134 | ### Android Architecture Components 135 | 136 | * Architecture Components 勉強会 第1回目 Lifecycles 137 | * https://speakerdeck.com/yanzm/architecture-components-mian-qiang-hui-di-1hui-mu-lifecycles 138 | * Architecture Components Playground 139 | * https://github.com/operando/Architecture-Components-Playground 140 | 141 | 142 | ### ARCore 143 | 144 | * https://developers.google.com/ar/ 145 | * https://developers-jp.googleblog.com/2017/08/arcore-android.html 146 | * ARCore 取扱説明書 (ARCore Developer Preview2に対応) 147 | * https://qiita.com/taptappun/items/a5337d29a43d5d673c7f 148 | 149 | 150 | ### Good Bye Jack、Welcome desugar 151 | 152 | * Java 8サポートにdesugarを使うようにしたぞい! 153 | * 昔はそこら辺Jackというものを使う話が進んでたけど移行コスト高いから?やめたみたいは感じ 154 | * https://developers-jp.googleblog.com/2017/03/future-of-java-8-language-feature.html 155 | * https://android-developers.googleblog.com/2017/03/future-of-java-8-language-feature.html 156 | * https://developer.android.com/studio/write/java8-support.html 157 | * https://android.googlesource.com/platform/external/desugar/ 158 | 159 | 160 | ### Next-generation Dex Compiler Now in Preview 161 | 162 | * D8ですね 163 | * Dexコンパイルが早くなる + Dexのサイズが小さくなる 164 | * Android Studio 3.1からデフォルトでD8が使われるようになる予定 165 | * R8は来年やっていき!っぽい 166 | * https://r8.googlesource.com/r8 167 | 168 | 169 | ### Next-generation Dex Compiler Now in Preview 170 | 171 | * https://android-developers.googleblog.com/2017/08/next-generation-dex-compiler-now-in.html 172 | * https://developers-jp.googleblog.com/2017/08/next-generation-dex-compiler-now-in.html 173 | 174 | 175 | ## ここから 私のやったこと振り返り 176 | 177 | ### DroidKaigi 2017で発表したねー 178 | 179 | * 2セッション話しました 180 | * Androidアプリ開発の体力づくり💪 181 | * コマンドなしでぼくはAndroid開発できない話 182 | * https://droidkaigi.github.io/2017/ 183 | 184 | 185 | ### Androidアプリ開発の体力づくり💪 186 | 187 | * 資料 188 | * https://speakerdeck.com/operando/androidapurikai-fa-falseti-li-dukuri 189 | * 資料の書き起こし 190 | * https://github.com/operando/DroidKaigi/tree/master/2017/muscle_android 191 | * これ動画残ってないの残念... 192 | * 話し直してYouTubeで配信しようかな 193 | 194 | 195 | ### コマンドなしでぼくはAndroid開発できない話 196 | 197 | * 資料 198 | * https://speakerdeck.com/operando/komantonasitehokuhaandroidkai-fa-tekinaihua-1 199 | * 資料の書き起こし 200 | * https://github.com/operando/DroidKaigi/tree/master/2017/no_command_no_life 201 | * 録画 202 | * https://academy.realm.io/jp/posts/droidkaigi17-android-development-with-commandline/ 203 | 204 | 205 | ### とあるアプリを作りました 206 | 207 | * 資料 208 | * https://speakerdeck.com/operando/merukari-kaurufalsekai-fa-qi-ninaru-narahua-sou 209 | * 今年も一からアプリ作ったので色々学べた 210 | * shibuya.apk #17 211 | * https://shibuya-apk.connpass.com/event/62499/ 212 | 213 | 214 | ### OnActivityResult熱高まる!! 215 | 216 | * OnActivityResult - おまえら!もうonActivityResultでswitchとif書く時代は終わりだぞ! 217 | * https://speakerdeck.com/operando/onactivityresult-omaera-mouonactivityresultdeswitchtoifshu-kushi-dai-hazhong-waridazo 218 | * コントリビュートもしたな 219 | * kyobashi.dex #4 220 | * https://rmp-quipper.connpass.com/event/47555/ 221 | 222 | 223 | ### ConstraintLayout はじめました 224 | 225 | * 頑張ってます 226 | * ConstraintLayout がもたらすパフォーマンスのメリットを理解する 227 | * https://developers-jp.googleblog.com/2017/09/understanding-performance-benefits-of.html 228 | * TechBooster's Playgroundの第1章 はじめてのConstraintLayout読みつつ触り始めてる 229 | * https://techbooster.booth.pm/items/715946 230 | 231 | 232 | ### アプリ間連携の仕組み について話しました 233 | 234 | * 資料 235 | * https://speakerdeck.com/operando/merukaritosouzouapurifalse-apurijian-lian-xi-falseshi-zu-mi-in-2017-summer 236 | * とりあえず知見の共有活動です 237 | * アプリいっぱいだして連携していこうな! 238 | 239 | 240 | ### VectorDrawable めっちゃ使った 241 | 242 | * 新しいアプリの画像はほとんどVectorDrawableにした 243 | * https://developer.android.com/guide/topics/graphics/vector-drawable-resources.html 244 | 245 | 246 | ### Retrofit ちゃんと使った 247 | 248 | * Making Retrofit Work For You (Ohio DevFest 2016) 249 | * https://speakerdeck.com/jakewharton/making-retrofit-work-for-you-ohio-devfest-2016 250 | * Converterを作るのに参考になった 251 | 252 | 253 | ### RxJava 2.0に移行した 254 | 255 | * What's different in 2.0 256 | * https://github.com/ReactiveX/RxJava/wiki/What%27s-different-in-2.0 257 | * RxJava 1.x → 2.x 移行ガイド 258 | * http://in.fablic.co.jp/entry/2017/04/27/110000 259 | * そこまで大変じゃなかったかなーWikiとか読めば 260 | 261 | 262 | ### Danger 導入した 263 | 264 | * http://danger.systems/ruby/ 265 | * 雑にいうと、Pull Requestのチェックを自動化するもの 266 | * Lintとかも含め 267 | * Android Danger Sample 268 | * https://github.com/operando/AndroidDangerSample 269 | * ここで試しに色々やってます 270 | 271 | 272 | ### Mobile Vision 使った 273 | 274 | * 主にScan Barcodes使った 275 | * https://developers.google.com/vision/ 276 | * めっちゃ便利 277 | * Camera APIを内部でラップしてて、カメラのハンドリングが難しい 278 | 279 | 280 | ### AsyncLayoutInflater の話したなー 281 | 282 | * 資料なしで話したので資料は残ってない 283 | * 非同期でレイアウトのinflateができるやつ 284 | * 短時間で膨大なViewを作る時には便利そう 285 | * AsyncLayoutInflater Sample 286 | * https://github.com/operando/AsyncLayoutInflater-Sample 287 | 288 | 289 | ### React Nativeちょっと触ってみた 290 | 291 | * Androiderから見るReact Native 292 | * https://speakerdeck.com/operando/androiderkarajian-rureact-native 293 | * もう一度 触ってみようかな 294 | * React.js meetup × React Native meetup 295 | * https://react-native-meetup.connpass.com/event/49024/ 296 | 297 | 298 | ### 技術書典 3で本書きました。ちょっとね。 299 | 300 | * Debug Menuはじめました。 301 | * https://techbookfest.org/event/tbf03 302 | * (続) Debug Menuはじめました。 303 | * https://speakerdeck.com/operando/sok-debug-menuhasimemasita 304 | * 書いた内容 + おまけの話した 305 | * shibuya.apk #19 306 | * https://shibuya-apk.connpass.com/event/68094/ 307 | 308 | 309 | ### Androidの本で読んだもの 310 | 311 | * Androidを支える技術〈Ⅰ〉──60fpsを達成するモダンなGUIシステム 312 | * http://gihyo.jp/book/2017/978-4-7741-8759-4 313 | * Androidを支える技術〈Ⅱ〉──真のマルチタスクに挑んだモバイルOSの心臓部 314 | * http://gihyo.jp/book/2017/978-4-7741-8861-4 315 | * 内容は簡単ではないけど、面白いし、Androidやっていく上で知ってるとよい 316 | 317 | 318 | ### あんどろいど ランチ はじめました 319 | 320 | * Androidの話しながらランチしようの会 321 | * https://android-lunch.connpass.com/ 322 | * 9月からはじめて今年5回もできた 323 | * 来年もやっていくぞ! 324 | 325 | 326 | ### Androidもくもくやろうぜ会 はじめました 327 | 328 | * 色んなエンジニアさんと交流したいぞ!って感じではじめた 329 | * https://mercari-android-mokumoku.connpass.com/ 330 | * 来年もぼちぼちやっていきます 331 | 332 | 333 | ### gummi 作った 334 | 335 | * JSON-RPC 2.0 Client Library 336 | * https://github.com/operando/gummi 337 | * 自作して社内アプリに組み込んでたやつをOSS化した 338 | * めっちゃ使っる 339 | 340 | 341 | ### OpenDroid 作った 342 | 343 | * 今開いてるAndroidのOpenGrokの別バージョンをさくっと開くChrome拡張作った 344 | * http://hack-it-iron.hatenablog.com/entry/2017/09/19/111520 345 | * https://github.com/operando/OpenDroid 346 | * わりと自分でそこそこ使ってる 347 | * 便利だよ! 348 | 349 | 350 | ## さいごまで ありがとうございました! 351 | -------------------------------------------------------------------------------- /第1回スタートアップAndroid勉強会/README.md: -------------------------------------------------------------------------------- 1 | # Lightweight-Stream-APIのあるAndroidアプリ開発 2 | 3 | ## SlideShare 4 | 5 | http://www.slideshare.net/shinobuokano7/lightweightstreamapiandroid 6 | 7 | ## Lightweight-Stream-API? 8 | 9 | * "Stream API from Java 8 rewritten on iterators for Java 7 and below." 10 | 11 | ## Lightweight-Stream-API? 12 | 13 | * https://github.com/aNNiMON/Lightweight-Stream-API 14 | 15 | ## Lightweight-Stream-API? 16 | 17 | * Androidでも使える!! 18 | 19 | 20 | ## ちなみに... 21 | 22 | * Lightweight-Stream-APIって名前が長い... 23 | * LSAって訳すっぽい 24 | * READMEにLSAって記述があった 25 | * 資料ないでLSAと書いてあるのは
Lightweight-Stream-APIという意味です 26 | 27 | 28 | ## Lightweight-Stream-API Includes 29 | 30 | * Functional interfaces 31 | * Stream/IntStream 32 | * Optional class 33 | * Exceptional class 34 | * Objects from Java 7 35 | 36 | 37 | ## Lightweight-Stream-API Includes 38 | 39 | * Streamだけじゃないんやでー!! 40 | 41 | 42 | ## Stream? 43 | 44 | * Java 8で導入されたAPI 45 | 46 | 47 | ## Stream? 48 | 49 | * "A sequence of elements supporting sequential and parallel aggregate operations." 50 | 51 | 52 | ## Stream(正しくはないけど雑に...) 53 | 54 | * 繰り返し処理のforやwhileをStreamにして、パイプライン的に処理する 55 | 56 | 57 | ## Lightweight-Stream-API 58 | 59 | * "without parallel processing but with a variety of additional methods and with custom operators" 60 | * parallelは提供されていない 61 | 62 | 63 | ## Lightweight-Stream-API ≠ Java 8 Stream API 64 | 65 | * イコールではない 66 | * Java 8 Stream APIのようなインターフェイスもったもの 67 | 68 | 69 | ## Streamの流れ 70 | 71 | * Streamの生成 72 | * 中間操作 (map,filter,etc.) 73 | * あるストリームを別のストリームに変換する操作 74 | * 終端操作 (forEach,count,collect,etc.) 75 | * 結果または副作用を生成する操作 76 | 77 | 78 | ## Java 8 Stream 79 | 80 | * スコアのListから30点以上のものを表示する 81 | * Java 8のCollectionにStreamに変換するメソッドがある 82 | 83 | ```java 84 | List scores = Arrays.asList(100, 30, 35, 20); 85 | scores.stream() // Streamの生成 86 | .filter(score -> score >= 30) // 中間操作 87 | .forEach(System.out::println); // 終端操作 88 | ``` 89 | 90 | 91 | ## for 92 | 93 | * スコアのListから30点以上のものを表示する 94 | 95 | ```java 96 | for (Integer score : scores) { 97 | if (score >= 30) { 98 | System.out.println(score); 99 | } 100 | } 101 | ``` 102 | 103 | 104 | ## Java 8 Parallel Stream 105 | 106 | * parallelStream()で並列処理 107 | * 並列で処理するので結果の順番は変わる可能性がある 108 | 109 | ```java 110 | List scores = Arrays.asList(100, 30, 35, 20); 111 | scores.parallelStream() 112 | .filter(score -> score >= 30) 113 | .forEach(System.out::println); 114 | ``` 115 | 116 | 117 | ## Lightweight-Stream-API 118 | 119 | * スコアのListから30点以上のものを表示する 120 | * Stream.ofでStreamを作る 121 | 122 | ```java 123 | List scores = Arrays.asList(100, 30, 35, 20); 124 | Stream.of(scores) // Streamの生成 125 | .filter(score -> score >= 30) // 中間操作 126 | .forEach(System.out::println); // 終端操作 127 | ``` 128 | 129 | 130 | ## 出力じゃなくてListにしたい!(Lightweight-Stream-API) 131 | 132 | * 終端操作をcollectにするだけなので簡単! 133 | 134 | ```java 135 | List scores = Arrays.asList(100, 30, 35, 20); 136 | List filteredScores = Stream.of(scores) 137 | .filter(score -> score >= 30) 138 | .collect(Collectors.toCollection(ArrayList::new)); 139 | ``` 140 | 141 | 142 | ## 中間操作、終端操作のメソッドは色々ある! 143 | 144 | * 全部説明できないので、javadocとかみて試してね! 145 | * 大体ほしいと思う機能は揃ってるはず 146 | * Stream - Lightweight-Stream-API javadoc 147 | * http://static.javadoc.io/com.annimon/stream/1.1.3/com/annimon/stream/Stream.html 148 | 149 | 150 | ## Lightweight-Stream-API 151 | 152 | * AndroidでJava 8のStreamっぽいものが使える! 153 | * 中間操作と終端操作は同じで書ける 154 | * 流れるように処理を書けるので気持ちいい! 155 | * Java力 UP 💪 156 | * Java 9でStreamに追加されるfunctionも使える! 157 | * good-bye for?? 158 | 159 | 160 | ## Optional 161 | 162 | 163 | ## Optional? 164 | 165 | * "A container object which may or may not contain a non-null value." 166 | 167 | 168 | ## Optional?(雑) 169 | 170 | * 値をラップしてnullかもしれないことを表現するクラス 171 | 172 | 173 | ## good-bye NullPointerException? 174 | 175 | * NO 😂 176 | 177 | 178 | ## Optional - Java 8 179 | 180 | ```java 181 | Optional optional = Optionalを返すメソッド(); 182 | optional.ifPresent(System.out::println); // nullでなければ表示される 183 | ``` 184 | 185 | ## Optional - Lightweight-Stream-API 186 | 187 | ```java 188 | Optional optional = Optionalを返すメソッド(); 189 | optional.ifPresent(System.out::println); // nullでなければ表示される 190 | ``` 191 | 192 | 193 | ## 同じや! 194 | 195 | * 同じや! 196 | 197 | 198 | ## Optional + Android 199 | 200 | * Android SDKのAPIって思った以上にnullを返すものが多い 201 | * ドキュメント読んで「え?null返るの?」と知るものも度々 202 | * FragmentねーgetContextとかgetActivityとか... 203 | * コードレビューでつっつかれたくない... 204 | * Fragment#getResourcesもmHostがnullだとIllegalStateException 205 | 206 | 207 | ## Fragment#getContext() 208 | 209 | * "Return the Context this fragment is currently associated with." 210 | * https://developer.android.com/reference/android/support/v4/app/Fragment.html#getContext() 211 | 212 | 213 | ## Fragment#getContext() 214 | 215 | * null返るやん👀 216 | 217 | ```java 218 | public Context getContext() { 219 | return mHost == null ? null : mHost.getContext(); 220 | } 221 | ``` 222 | 223 | 224 | ## Fragment + Optional 225 | 226 | ```java 227 | public static Optional getOptionalContext(Fragment fragment) { 228 | if (fragment.isDetached()) { 229 | return Optional.empty(); 230 | } 231 | return Optional.ofNullable(fragment.getContext()); 232 | } 233 | 234 | // 安全! 235 | FragmentUtil.getOptionalContext(this) 236 | .ifPresent(context -> { 237 | Toast.makeText(context, "Optional最高!", Toast.LENGTH_SHORT).show(); 238 | }); 239 | ``` 240 | 241 | 242 | ## Fragment + Optional 243 | 244 | ```java 245 | public static Optional getOptionalFragmentActivity(Fragment fragment) { 246 | if (fragment.isDetached()) { 247 | return Optional.empty(); 248 | } 249 | return Optional.ofNullable(fragment.getActivity()); 250 | } 251 | 252 | // menuの更新 253 | // 安全! 254 | FragmentUtil.getOptionalFragmentActivity(this) 255 | .ifPresent(FragmentActivity::supportInvalidateOptionsMenu); 256 | ``` 257 | 258 | 259 | ## Fragment + Optional 260 | 261 | ```java 262 | public static Optional getArguments(Fragment fragment) { 263 | return Optional.ofNullable(fragment.getArguments()); 264 | } 265 | 266 | // 安全! 267 | FragmentUtil.getArguments(this) 268 | .ifPresent(bundle -> { 269 | // bundleから値を取り出す 270 | }); 271 | ``` 272 | 273 | 274 | ## 複数のOptionalを扱う 275 | 276 | * Optional AとOptional Bの両方がnullでなければ...みたいなパターン 277 | * そもそもこれで正しいのかわからない... 278 | 279 | ```java 280 | Optional optionalFragmentActivity = FragmentUtil.getOptionalFragmentActivity(this); 281 | Optional titleOptional = titleをOptionalで返すメソッド(); 282 | optionalFragmentActivity.ifPresent(fragmentActivity -> { 283 | titleOptional.ifPresent(title -> { 284 | fragmentActivity.setTitle(title); 285 | }); 286 | }); 287 | ``` 288 | 289 | ## 複数のOptionalを扱う 290 | 291 | * これならどうだ💪 292 | * Tupleで2つのOptionalに値が入っていれば、TupleをOptionalでラップして返す 293 | 294 | ```java 295 | public static Optional> flatMapPair(Optional a, Optional b) { 296 | if (a.isPresent() && b.isPresent()) { 297 | // 2つのOptionalに値が入っていればTupleをOptionalでラップして返す 298 | return Optional.ofNullable(Pair.create(a.get(), b.get())); 299 | } else { 300 | // そうでないならempty 301 | return Optional.empty(); 302 | } 303 | } 304 | 305 | OptionalUtil.flatMapPair(optionalFragmentActivity,titleOptional) 306 | .ifPresent(pair -> { 307 | pair.getFirst()setTitle(pair.getSecond()); 308 | }); 309 | 310 | ``` 311 | 312 | ## 複数のOptionalを扱う💪💪💪 313 | 314 | ```java 315 | public static Optional> flatMapTriplet(Optional a, Optional b, Optional c) { 316 | if (a.isPresent() && b.isPresent() && c.isPresent()) { 317 | return Optional.ofNullable(Triplet.create(a.get(), b.get(), c.get())); 318 | } else { 319 | return Optional.empty(); 320 | } 321 | } 322 | ``` 323 | 324 | 325 | ## 💪 326 | 327 | * 💪 328 | 329 | 330 | ## でも、JavaにTupleないやん... 331 | 332 | 333 | ## Guild 334 | 335 | * 💪 336 | * Simple java tuples. 337 | * https://github.com/operando/Guild 338 | 339 | 340 | ## Lightweight-Stream-APIのOptionalにしかない便利なメソッド 341 | 342 | * Optional.stream() 343 | * OptionalからStreamに変換できる 344 | * 他にもいくつかある... 345 | 346 | ```java 347 | Optional.ofNullable(integers) 348 | .stream() 349 | .forEach(System.out::println); 350 | ``` 351 | 352 | * Java8だと 353 | 354 | ```java 355 | Optional.ofNullable(integers) 356 | .map(integers1 -> integers1.stream()) 357 | .orElse(Stream.empty()) 358 | .forEach(System.out::println); 359 | ``` 360 | 361 | ## Optionalにも中間操作、終端操作的なのがある 362 | 363 | * 中間操作?的なの 364 | * map,flagMap,filter,etc... 365 | * 終端操作?的なの 366 | * ifPresent,orElse,etc... 367 | 368 | ## Optional 369 | 370 | * Optional javadoc - Lightweight-Stream-API 371 | * http://static.javadoc.io/com.annimon/stream/1.1.3/com/annimon/stream/Optional.html 372 | 373 | 374 | ## Optional 375 | 376 | * AndroidでJava 8のOptionalと同じようなものが使える 377 | * Java力 UP💪 378 | * ifでnullチェックするより自然な感じでプログラムが書ける 379 | * nullがなくなるわけではない 380 | * 扱いが難しいこともある 381 | * Optionalのラップしてる値がnullだった時の処理を忘れるとか... 382 | 383 | 384 | ## Objectsもいいぞ! 385 | 386 | * Java 7から追加されたAPI 387 | * AndroidではminSdkVersion 19以上じゃないとJava 7のAPIは使えないはず 388 | 389 | ## Objectsもいいぞ! 390 | 391 | * 2つの文字列を比較したい 392 | 393 | ```java 394 | String s1 = String返すメソッド(); 395 | String s2 = String返すメソッド(); 396 | 397 | // s1はnullかもしれない... 398 | s1.equals(s2); 399 | 400 | // Lightweight-Stream-API 401 | // どちらかがnullでも安全! 402 | Objects.equals(s1,s2); 403 | ``` 404 | 405 | ## Andorid N minSdkVersion 24 406 | 407 | * Java 8のAPIがいくつか入ってる 408 | * StreamとOptionalは入ってる 409 | * 他にもいくつか... 410 | * Lightweight-Stream-API使わなくてもよい 411 | * minSdkVersion 24...何年先? 412 | 413 | 414 | ## Android-Java-8-Stream-Example 415 | 416 | * Lightweight-Stream-APIの作者がAndroidでJava 8っぽく書くサンプルを書いてる 417 | * https://github.com/aNNiMON/Android-Java-8-Stream-Example 418 | 419 | 420 | ## まとめ 421 | 422 | * Lightweight-Stream-APIを使えばStreamっぽいものとOptionalが使える 423 | * それ以外にも便利な機能あるよ! 424 | * Java力 UP💪につながる 425 | * Android開発のJavaだとJava 6,7で技術が止まってしまう可能性も... 426 | * 僕と一緒に開発する人にはJavaの力もつけてほしい💪 427 | * Java 9も来年出るのでJava自体に関心を! 428 | 429 | ## Links 430 | 431 | * Lightweight-Stream-API version 1.1.3 javadoc 432 | * http://static.javadoc.io/com.annimon/stream/1.1.3/overview-summary.html 433 | * Stream - Java 8 434 | * https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html 435 | * Java 8 Stream Tutorial 436 | * http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ 437 | * Optional - Java 8 438 | * https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html 439 | * Optionalの取り扱いかた 440 | * http://irof.hateblo.jp/entry/2015/05/05/071450 441 | 442 | ## Thanks 443 | -------------------------------------------------------------------------------- /第1回スタートアップAndroid勉強会/memo.md: -------------------------------------------------------------------------------- 1 | 2 | ## Optionalの注意点?? 3 | 4 | 引数でOptionalを取るようなものはよくない 5 | 6 | 戻り値としてOptionalを扱う 7 | 8 | 戻り値がOptionalじゃないけど、nullが返ってくるかもしれないものをOptionalで包む 9 | or 10 | Optionalでラップするメソッドを作る 11 | 12 | 13 | ## よく使用するメソッド 14 | 15 | empty 16 | flatMap 17 | map 18 | ifPresent 19 | ofNullable 20 | orElse 21 | orElseGet 22 | 23 | filter?(使うかな?) 24 | 25 | 26 | ## of、isPresent、getの使いみちは限られる 27 | 28 | ```Java 29 | // Optionalオブジェクトを生成するofメソッドは、引数がnullだとヌルポを投げる… 30 | Optional hogeOpt = Optional.of(getHoge()); 31 | 32 | if (hogeOpt.isPresent()) { // 値が存在しているか? => 従来のnullチェックと同じことをしている… 33 | 34 | // 値を取得するgetメソッドは、値が存在していない場合実行時例外を投げる…(NoSuchElementException) 35 | String hoge = hogeOpt.get(); 36 | 37 | System.out.println(hoge); 38 | } 39 | ``` 40 | 41 | 42 | ## memo 43 | 44 | Optionalを戻り値としたメソッドは決してnullを返すべきでないが、それを防ぐ方法はない 45 | 未熟な者や無法者はどこにでもいる 46 | 47 | Optionalを使っているが処理構造に変化が無い 48 | Optionalを使わない時よりもコードが増えている 49 | 50 | Optional#flatMapでnullを返してはいけない 51 | 52 | 53 | 54 | Java8とのAPIとの比較 55 | 56 | Java8にはあるけど、L-S-APIにちょっと無くて残念な機能 57 | 58 | Optionalをどう扱うか 59 | 60 | 61 | 62 | Lightweight-Stream-API 63 | https://github.com/aNNiMON/Lightweight-Stream-API 64 | 65 | Android Optional 66 | https://developer.android.com/reference/java/util/Optional.html 67 | 68 | Java Optional 69 | https://docs.oracle.com/javase/jp/8/docs/api/java/util/Optional.html 70 | https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html 71 | 72 | RxJavaのObservableでOptionalを代行する 73 | http://sys1yagi.hatenablog.com/entry/2015/01/26/183000 74 | 75 | RxJava-Optional 76 | https://github.com/eccyan/RxJava-Optional 77 | 78 | 79 | Optionalの取り扱いかた 80 | http://irof.hateblo.jp/entry/2015/05/05/071450 81 | 82 | 83 | Android-Java-8-Stream-Example 84 | https://github.com/aNNiMON/Android-Java-8-Stream-Example 85 | -------------------------------------------------------------------------------- /開発×テスト LT会 - vol.2 #devtestlt/README.md: -------------------------------------------------------------------------------- 1 | # CircleCIでtiming dataに基づいたテスト分割をDartで利用できるようにした話 2 | 3 | ## timing dataの話をする上ので前提知識 4 | 5 | ## CircleCIのテストメタデータ 6 | 7 | - テスト結果が記載されたファイルのこと(雑) 8 | - テストメタデータを活用するとTest Insightsなどが利用できる 9 | - timing dataはテストメタデータから生成される 10 | 11 | ## CircleCIのテストメタデータ 12 | 13 | - Collecting test data 14 | - https://circleci.com/docs/2.0/collect-test-data/ 15 | 16 | ## CircleCIでテストメタデータを保存する 17 | 18 | - store_test_resultsステップでテスト結果(テストメタデータ)を保存する 19 | - https://circleci.com/docs/ja/2.0/configuration-reference/#storetestresults 20 | 21 | ## CircleCIでテストメタデータを保存する 22 | 23 | ```yaml 24 | - store_test_results: 25 | path: test-results 26 | ``` 27 | 28 | ## CircleCIのテストメタデータ フォーマット 29 | 30 | - CircleCIでテスト結果がテストメタデータと認識されるフォーマットは以下 31 | - JUnit XML 32 | - Cucumber JSON 33 | - 多くの言語ライブラリでサポートしているのはJUnit XML 34 | - 本資料でもJUnit XMLを扱います 35 | 36 | ## JUnit XML Schema 37 | 38 | - https://github.com/windyroad/JUnit-Schema 39 | - https://github.com/sj26/rspec_junit_formatter/blob/main/lib/rspec_junit_formatter.rb#L9-L11 40 | - http://windyroad.org/dl/Open%20Source/JUnit.xsd 41 | 42 | ## CircleCIのテスト分割と並列実行 43 | 44 | - 1つの実行環境(Executor)で全テストを実行するとCIの実行時間が長くなる 45 | - CircleCIにはテストを複数のExecutorに分割させるためのコマンドがある 46 | - コマンドで分割したテストを複数のExecutorで並列実行させることにより全テスト実行が早くなり、CIの実行時間も短くなる 47 | 48 | ## CircleCIのテスト分割と並列実行 49 | 50 | - Running Tests in Parallel 51 | - https://circleci.com/docs/2.0/parallelism-faster-jobs/ 52 | 53 | ## CircleCIのテスト分割と並列実行 54 | 55 | ![test_splitting](images/test_splitting.png) 56 | 57 | - 公式ドキュメントの図をお借りして説明するとこんな感じ 58 | - 一番下がtiming dataに基づいたパターンの説明 59 | 60 | ## テスト分割 61 | 62 | - 分割の仕方によって全体のテスト実行時間に影響する 63 | - 適当に分割して並列実行させると環境ごとに実行時間にばらつきが出る 64 | - 可能なかぎり環境ごとの実行時間のばらつきが小さくなるように分割するのがよい✨ 65 | 66 | ## 最適なテスト分割 67 | 68 | - 各テストケースの実行にかかる時間を計測する 69 | - 計測した時間を利用し全体のテスト時間が短くなるよういい感じのアルゴリズムでいい感じに分割する 70 | - 「いい感じ」が大事😊 71 | 72 | ## 最適なテスト分割とは 73 | 74 | - circleci tests split --split-by=timingsについて調べた・自作してみた 75 | - https://hoshinotsuyoshi.com/post/circleci_tests_split/ 76 | 77 | ## CircleCIのテスト分割 78 | 79 | - 以下の分割方法をサポートしている 80 | - タイミングデータ(timing data) 81 | - ファイル名・クラス名 82 | - ファイルサイズ 83 | - CircleCIはtiming dataによる分割が最良の方法としてる 84 | 85 | ## CircleCIのtiming data 86 | 87 | - 各テストケースの実行時間が記載されているJSONファイル 88 | - テストメタデータを元にCircleCIがtiming dataを生成する 89 | - timing dataの内容は確認できる 90 | 91 | ## CircleCIのtiming data 92 | 93 | - 各テストケースの結果には、クラス名とファイル名などが記載されていることをCircleCIは期待している 94 | - 各テストファイルのテスト実行にかかる時間がわかるデータ構造 95 | - デフォルトの分割方法が、ファイル名に基づいた分割なので上記が必要 96 | - テストメタデータにそれらの情報が記載されていないとtiming dataを利用しても思ったとおりにテスト分割が実行されない 97 | 98 | ## timing dataを利用してテスト分割して実行する例(rspec) 99 | 100 | ```ruby 101 | circleci tests glob "test/**/*.rb" | circleci tests split --split-by=timings > /tmp/tests-to-run 102 | bundle exec rspec $(cat /tmp/tests-to-run) 103 | ``` 104 | 105 | ## timing dataを利用してテスト分割して実行する例(rspec) 106 | 107 | - circleci tests splitでテストファイルの一覧取得 108 | - --split-by=timingsでtiming dataを利用し実行環境ごとにテスト分割を行うように指定 109 | - bundle exec rspecへ実行環境ごとに分割されたテストを実行するように指定 110 | 111 | ## Dartのtestについて 112 | 113 | ## Why Dart test? 114 | 115 | - 私が所属する会社 10Xで作っているサービス StailerではAPI実装にサーバーサイドDartを使用 116 | - サーバーサイドDartではCIにCircleCIを利用している 117 | - Dartでテストを書く場合「test」パッケージがメジャー 118 | - https://pub.dev/packages/test 119 | 120 | ## Dart sharding tests 121 | 122 | - testパッケージにはテスト分割する機能がある!! 123 | - 現在 10Xではtestの機能を使ってCircleCI上でテストを分割・並列実行している 124 | - しかし、この分割方法は各テストケースの実行時間などを元にテスト分割されるわけではない 125 | - そのためExecutorごとに実行時間のばらつきが大きいのが課題 126 | 127 | ## Dart sharding tests 128 | 129 | ```ruby 130 | dart test --total-shards 3 --shard-index 0 path/to/test.dart 131 | dart test --total-shards 3 --shard-index 1 path/to/test.dart 132 | dart test --total-shards 3 --shard-index 2 path/to/test.dart 133 | ``` 134 | 135 | ## Dart sharding tests 136 | 137 | - testパッケージのテスト分割の実装 138 | - https://github.com/dart-lang/test/blob/2afbff8cc059b37b4b1a69fc2ddffc53290e4780/pkgs/test_core/lib/src/runner.dart#L428-L443 139 | 140 | 141 | ## Dart testsでCircleCIのtiming dataを利用してもっといい感じにテスト分割・並列実行したい!と思ったわけで… 142 | 143 | ## Dart testの結果をJunit XMLで出力する 144 | 145 | - Dart testはテスト結果をJSON出力する機能がある 146 | - https://github.com/dart-lang/test/blob/master/pkgs/test/doc/json_reporter.md 147 | - そのJSON出力された結果をJunit XMLに変換するツールがある 148 | - https://github.com/TOPdesk/dart-junitreport 149 | - これを使ってDart testのテスト結果をJunit XMLで出力する 150 | 151 | ## 出力したJunit XMLをテストメタデータとしてCircleCIに認識させる 152 | 153 | - store_test_resultsステップにJunit XMLを出力したディレクトリを指定する 154 | - これでテスト結果のJunit XMLがCircleCIにテストメタデータとして認識される 155 | - 認識したテストメタデータを元にCircleCIがtiming dataを生成する 156 | 157 | ## テスト実行のコマンドを書き換える 158 | 159 | - timing dataを利用してテスト分割を行い、分割したファイルのみでテスト実行するようにコマンドを書き換える 160 | 161 | ```ruby 162 | TESTFILES=$(circleci tests glob "test/**/*_test.dart" | circleci tests split --split-by=timings) 163 | dart run test ${TESTFILES} --file-reporter json:test_results/tests_report.json --reporter expanded 164 | ``` 165 | 166 | 167 | ## よし、これで完璧✨✨✨✨ 168 | 169 | 170 | ## では...なかった...💥💥💥💥 171 | 172 | 173 | ## 何が起きたか...😨 174 | 175 | - "No timing found for <ファイル名>"というメッセージが出た 176 | - テストファイルに対するtiming dataが存在しないぜ!って言ってる 177 | - timing dataのファイルは生成されていたが、何かしらの原因でうまく利用されていないので、最適なテスト分割が行えていない 178 | 179 | ### timing dataのファイルを確認する方法 180 | 181 | ```ruby 182 | cat ${CIRCLE_INTERNAL_TASK_DATA}/circle-test-results/results.json 183 | ``` 184 | 185 | ## 何がダメだったか...😱 186 | 187 | - timing dataを確認してみてわかったのが、各テストケースがどのテストファイルに記載されているのかを示すfile keyの値がnullだった 188 | 189 | ![file_null](images/file_null.png) 190 | 191 | ## 何がダメだったか...まとめると...😱 192 | 193 | - 各テストケースの実行時間などは記載されているが各テストケースがどのファイルに記載されているのかを示す値がnullなので、テストファイルごとの実行時間が計算できない 194 | - 結果、うまくテスト分割できないわ!って感じだった 195 | 196 | 197 | ## file keyの値がnullな原因を探る 198 | 199 | - timing dataはテストメタデータから生成される 200 | - テストメタデータ = テスト結果が記載されたJunit XMLを確認してみた 201 | 202 | ## 出力されたJunit XMLの内容 203 | 204 | ```xml 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | ``` 221 | 222 | ## file keyの値がnullな原因を探る 223 | 224 | - testcase elementに各テストケースの結果が記載されている 225 | - そこに各テストケースが記載されているテストファイル名が書かれていないがないことが原因っぽいことがわかった 226 | - 原因がわかったのでtestcase elementにfile attributeの追加を試みた 227 | 228 | ## 試してみた修正 229 | 230 | - dart-junitreportの内部で利用されているdart-testreportライブラリの修正 231 | - dart-junitreportでJunit XML出力する際、testcase elementにfile attributeの追加 232 | - file attributeに記載されたfile pathをCI上でsedコマンドを利用して書き換え 233 | 234 | ## 修正してみた結果 235 | 236 | - Dart testでもtiming dataを利用して最適なテスト分割ができるようになった! 237 | - めでたい🎉🎉🎉🎉 238 | 239 | ## 完成形がこちら💪 240 | 241 | - CircleCIでtiming dataに基づいたテスト分割をDartで利用できるようにするサンプルプロジェクト 242 | - https://github.com/operando/dart-test-CircleCI-timing-data 243 | - サンプルプロジェクトのCircleCIの結果 244 | - https://app.circleci.com/pipelines/github/operando/dart-test-CircleCI-timing-data/14/workflows/e4884496-b4b0-4d5b-af7a-0209097affac/jobs/16 245 | 246 | ## 完成形の.circleci/config.ymlの内容 247 | 248 | ```yaml 249 | version: 2.1 250 | 251 | jobs: 252 | test: 253 | docker: 254 | - image: dart:2.16.1 255 | parallelism: 2 256 | steps: 257 | - checkout 258 | - run: 259 | name: Download dependencies 260 | command: pub get 261 | - run: 262 | name: Test 263 | command: | 264 | cat ${CIRCLE_INTERNAL_TASK_DATA}/circle-test-results/results.json 265 | TESTFILES=$(circleci tests glob "test/**/*_test.dart" | circleci tests split --split-by=timings) 266 | echo ---------------- 267 | echo ${TESTFILES} 268 | dart run test ${TESTFILES} --file-reporter json:test_results/tests_report.json --reporter expanded 269 | - run: 270 | name: Install JUnitReport 271 | when: always 272 | command: dart pub global activate --source git https://github.com/operando/dart-junitreport.git 273 | - run: 274 | name: Convert tests to JUnit 275 | when: always 276 | command: | 277 | $HOME/.pub-cache/bin/tojunit --input test_results/tests_report.json --output test_results/tests_report_junit.xml 278 | sed -i -e "s|file:///root/project/||g" test_results/tests_report_junit.xml 279 | - store_test_results: 280 | path: test_results/ 281 | - store_artifacts: 282 | path: test_results/ 283 | 284 | workflows: 285 | version: 2 286 | build: 287 | jobs: 288 | - test 289 | ``` 290 | 291 | ## .circleci/config.ymlの内容で大事なところはここ! 292 | 293 | ```yaml 294 | # これでこの部分のテスト分割がうまく動いた! 295 | - run: 296 | name: Test 297 | command: | 298 | TESTFILES=$(circleci tests glob "test/**/*_test.dart" | circleci tests split --split-by=timings) 299 | dart run test ${TESTFILES} --file-reporter json:test_results/tests_report.json --reporter expanded 300 | # forkしたリポジトリに修正を入れたので自身のリポジトリから取得 301 | - run: 302 | name: Install JUnitReport 303 | when: always 304 | command: dart pub global activate --source git https://github.com/operando/dart-junitreport.git 305 | # Junit XMLで出力し、sedでfile attributeの内容を書き換え 306 | - run: 307 | name: Convert tests to JUnit 308 | when: always 309 | command: | 310 | $HOME/.pub-cache/bin/tojunit --input test_results/tests_report.json --output test_results/tests_report_junit.xml 311 | sed -i -e "s|file:///root/project/||g" test_results/tests_report_junit.xml 312 | # 出力したJunit XMLを保存! 313 | - store_test_results: 314 | path: test_results/ 315 | - store_artifacts: 316 | path: test_results/ 317 | ``` 318 | 319 | ## やったね😊!! 320 | -------------------------------------------------------------------------------- /開発×テスト LT会 - vol.2 #devtestlt/images/file_null.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/開発×テスト LT会 - vol.2 #devtestlt/images/file_null.png -------------------------------------------------------------------------------- /開発×テスト LT会 - vol.2 #devtestlt/images/test_splitting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/operando/Notes/4801eb72e95755793d36f1ded9e3eced3b17431c/開発×テスト LT会 - vol.2 #devtestlt/images/test_splitting.png --------------------------------------------------------------------------------