Slide 1

Slide 1 text

4೥ଓ͘ΞϓϦʹ͓͚Δ νʔϜ։ൃ @cutmail ϋογϡλάɿ#DroidKaigi2

Slide 2

Slide 2 text

ର৅ऀ • AndroidΞϓϦͷνʔϜ։ൃΛ͍ͯ͠Δ • AndroidΞϓϦͷνʔϜ։ൃʹڵຯ͕͋Δ • AndroidΞϓϦͷνʔϜ։ൃΛ͍ͯͯ͠Կ͔ ࠔ͍ͬͯΔ

Slide 3

Slide 3 text

ΞδΣϯμ • ϑϦϧAndroid൛ͷي੻ • ϑϦϧʹ͓͚Δ։ൃ • νʔϜ։ൃΛ͏·͘ճͨ͢Ίʹ΍͖ͬͯͨ͜ ͱ

Slide 4

Slide 4 text

@cutmail • גࣜձࣾFablic Co-Founder/Engineer • Android / iOS / Ruby on Rails

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

ϑϦϧ

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

ϑϦϧ • ೔ຊॳͷϑϦϚΞϓϦ • ౰ॳ͸ঁੑݶఆɺͷͪʹஉੑʹղ์ • 2012೥7݄ʹiOS൛͕ϦϦʔε

Slide 9

Slide 9 text

ϑϦϧ for iOS • ౰࣌͸Titanium MobileͰ։ൃ։࢝ • ։ൃظؒ໿3ϲ݄ • ͷͪʹ༷ʑͳࣄ৘ͰωΠςΟϒԽ

Slide 10

Slide 10 text

͓΅͍͑ͯ·͔͢
 Titanium Mobile

Slide 11

Slide 11 text

Titanium Mobile • ౰࣌͸JavascriptͰΫϩεϓϥοτϑΥʔϜ։ ൃ͕Ͱ͖ΔͱݴΘΕ͍ͯͨ • ౰࣌ͷTitanium MobileͰͷAndroidΞϓϦ։ ൃ͸

Slide 12

Slide 12 text

ϑϦϧ for Android Java!

Slide 13

Slide 13 text

ϑϦϧ for Android • 2012೥11݄6೔ ॳgitίϛοτ • 2013೥1݄29೔ v1.0ϦϦʔε • ࠷ۙKotlin͕ಋೖ͞Ε·ͨ͠

Slide 14

Slide 14 text

v1.0

Slide 15

Slide 15 text

Լλϒ!!!

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

• ϑϦϧAndroid൛ͷي੻ • ϑϦϧʹ͓͚Δ։ൃ • νʔϜ։ൃΛ͏·͘ճͨ͢Ίʹ΍͖ͬͯͨ͜ ͱ ΞδΣϯμ

Slide 18

Slide 18 text

• v1.0 • v2.1 • ެࣜγϣοϓػೳ௥Ճ • v2.3 • ActionBarԽ • σβΠϯϦχϡʔΞϧ • v2.5 • FrilAPIClient΁ͷҠߦ • v3.0 • UIϦχϡʔΞϧ • v3.6 • ͓͢͢ΊϢʔβʔϦ χϡʔΞϧ • v4.0 • UIϦχϡʔΞϧ • v4.1.2 • RxAndroid1.0ʹߋ৽ • v4.3 • Android WearΞϓϦ ͷ௥Ճ • v5.0 • ৭ݕࡧػೳͷ௥Ճ • v5.2 • ͕͢͞ը໘ϦχϡʔΞ ϧ • v5.3.2 • νϟοταϙʔτ • v5.5.0 • FCM΁ͷҠߦ • v5.7.0 • λΠϜϥΠϯɾ͕͢͞ ը໘ϦχϡʔΞϧ • v6.0 • v6.0.0 BIϦχϡʔΞ ϧɾϒϥϯυ&ੑผબ ୒ഇࢭ • v6.4 • SMSೝূ

Slide 19

Slide 19 text

• v1.0 • v2.1 • ެࣜγϣοϓػೳ௥Ճ • v2.3 • ActionBarԽ • σβΠϯϦχϡʔΞϧ • v2.5 • FrilAPIClient΁ͷҠߦ • v3.0 • UIϦχϡʔΞϧ • v3.6 • ͓͢͢ΊϢʔβʔϦ χϡʔΞϧ • v4.0 • UIϦχϡʔΞϧ • v4.1.2 • RxAndroid1.0ʹߋ৽ • v4.3 • Android WearΞϓϦ ͷ௥Ճ • v5.0 • ৭ݕࡧػೳͷ௥Ճ • v5.2 • ͕͢͞ը໘ϦχϡʔΞ ϧ • v5.3.2 • νϟοταϙʔτ • v5.5.0 • FCM΁ͷҠߦ • v5.7.0 • λΠϜϥΠϯɾ͕͢͞ ը໘ϦχϡʔΞϧ • v6.0 • BIϦχϡʔΞϧɾϒϥ ϯυ&ੑผબ୒ഇࢭ • v6.4 • SMSೝূ

Slide 20

Slide 20 text

ΞϓϦΞΠίϯͷมԽ

Slide 21

Slide 21 text

ϑϦϧͷྺ࢙͸ ϦχϡʔΞϧͷྺ࢙

Slide 22

Slide 22 text

ϦχϡʔΞϧ͸༷ʑͳ൓Ԡ͕ ى͖Δ

Slide 23

Slide 23 text

https://speakerdeck.com/shoby/yuzanishou-keru-rerare-wen-ti-woqi-kosiduraida-gui-mo-riniyuarufalsejin-mefang

Slide 24

Slide 24 text

• v1.0~ • v2.0~ • v3.5~

Slide 25

Slide 25 text

։ൃମ੍ • AndroidΞϓϦΤϯδχΞ 1.5໊ • ࣗ෼͸iOSΛ΍Γͳ͕ΒยखؒAndroid • σβΠφʔ 1໊ v1.0~v1.1 ♂♂

Slide 26

Slide 26 text

։ൃ؀ڥ • Eclipse • Bitbucket « v1.0~v1.1

Slide 27

Slide 27 text

։ൃϑϩʔ • ϓϧϦΫΤετɺίʔυϨϏϡʔ͸ͳ͠ • developϒϥϯν͔ΒͦΕͧΕϒϥϯνΛ੾ͬ ֤ͯࣗͰϚʔδ • جຊతʹ͸iOSͷػೳΛͦͷ··Ҡ২ v1.0~v1.1

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

ΞʔΩςΫνϟ • Activity • DB • Content Provider • ը૾ಡΈࠐΈ • URLConnectionʹΑΔࣗલ࣮૷ v1.0~v1.1

Slide 31

Slide 31 text

ΞʔΩςΫνϟ • API • AsyncTaskLoaderϕʔε • ը໘ؒͷΠϕϯτ௨஌ • startActivityForResult • ্෦ͷόʔ͸ࣗલ v1.0~v1.1

Slide 32

Slide 32 text

v1.0~v1.1 public Loader onCreateLoader(int index, Bundle args) { HashMap params = new HashMap(); params.put("method", "0"); params.put("grid_flag", "0"); params.put("pos", "0"); Loader loader = new JSONLoader(this, "POST", “/timeline", params); loader.forceLoad(); return loader; } @Override public void onLoadFinished(Loader arg0, JSONObject response) { if (response == null) return; mAdapter.loadFromJSON(response); if (mAdapter.getCount() > 0) { mListView.setAdapter(mAdapter); mListView.invalidate(); } } AsyncTaskLoader APIίʔϧ APIϨεϙϯε

Slide 33

Slide 33 text

• v1.0~v1.1 • v2.0~ • v3.5~

Slide 34

Slide 34 text

v2.3

Slide 35

Slide 35 text

v3.0

Slide 36

Slide 36 text

ମ੍ • AndroidΞϓϦΤϯδχΞ 5໊ • σβΠφʔ 1໊ v2.0~v3.4 ♂♂♂ ♂♂

Slide 37

Slide 37 text

։ൃ؀ڥ • GitHub • Android Studio • Gradle • CI (Travis-CI) v2.0~

Slide 38

Slide 38 text

։ൃϑϩʔ • ϓϧϦΫΤετಋೖ • ίʔυϨϏϡʔಋೖ v2.0~

Slide 39

Slide 39 text

ΞʔΩςΫνϟ • Activity + Fragment • ԣը໘ɺλϒϨοτରԠͷͨΊʹFragmentͷಋೖ • DB • Content Provider • ը૾ಡΈࠐΈ • Picasso v2.0~

Slide 40

Slide 40 text

ΞʔΩςΫνϟ • API • android-async-http • EventBus • Otto v2.0~

Slide 41

Slide 41 text

public RequestHandle getItemDetail(int itemId, final SingleModelCallback callback) {
 RequestParams params = new RequestParams(baseParams);
 params.put("item_id", String.valueOf(itemId));
 
 return httpClient.get(baseUrl + "/api/item", params, new JsonHttpResponseHandler() {
 @Override
 public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
 ItemDetail itemDetail = gson.fromJson(response.toString(), ItemDetail.class);
 callback.success(itemDetail);
 }
 
 @Override
 public void onFailure(int statusCode, Throwable e, JSONObject errorResponse) {
 callback.failure(statusCode, e, errorResponse);
 }
 });
 } android-async-http v2.0~

Slide 42

Slide 42 text

private void getItemDetail() { apiClient.getItemDetail(mItem.getId(),new FrilAPIClient.SingleModelCallback() { @Override public void success(ItemDetail itemDetail) { setDetailView(itemDetail); } @Override public void failure(int statusCode, Throwable error, JSONObject errorResponse) { // Τϥʔॲཧ } }); } android-async-http v2.0~

Slide 43

Slide 43 text

• v1.0~ • v2.0~ • v3.5~

Slide 44

Slide 44 text

v4.0

Slide 45

Slide 45 text

։ൃମ੍ • AndroidΞϓϦΤϯδχΞ 2໊ • σβΠφʔ 1໊ v3.5~ ♂♂

Slide 46

Slide 46 text

։ൃ؀ڥ v3.5~ • GitHub • Android Studio • Gradle • CI (CircleCI)

Slide 47

Slide 47 text

ΞʔΩςΫνϟ • Activity + Fragment • DB • Content Provider v3.5~

Slide 48

Slide 48 text

ΞʔΩςΫνϟ • API • Retrofit + RxJava v3.5~

Slide 49

Slide 49 text

Observable observable = FrilServiceCreator.createFrilService(activity).getItemDetail(itemId);
 return observable.subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(new Action1() {
 @Override
 public void call(ItemDetail itemDetail) { setItemDetail(itemDetail);
 }
 }, new Action1() {
 @Override
 public void call(Throwable throwable) {
 Timber.e(throwable, throwable.getMessage());
 }
 }); Retrofit + RxJava v3.5~ @GET("/api/item")
 Observable getItemDetail(
 @Query("item_id") Integer itemId
 );

Slide 50

Slide 50 text

ΞʔΩςΫνϟͷมભ

Slide 51

Slide 51 text

ΞʔΩςΫνϟͷมભ ωοτϫʔΫ "TZOD5BTL-PBEFS BOESPJE BTZODIUUQ 3FUSPpU ඇಉظॲཧ ΠϯλϑΣʔε -PBEFS $BMMCBDL 3Y+BWB &WFOU#VT TUBSU"DUJWJUZ'PS3FTVMU 0UUP 0UUP ը૾ 63-$POOFDUJPO 1JDBTTP 1JDBTTP

Slide 52

Slide 52 text

RxJavaΛಋೖ͢Δ·Ͱ͸…

Slide 53

Slide 53 text

ྫ͑͹ɺΞϓϦ಺ͷϚελσʔλ ʢۜߦɺϒϥϯυʣ ͷߋ৽

Slide 54

Slide 54 text

ྫʣϚελσʔλͷߋ৽ॲཧ 1. Ϛελσʔλͷߋ৽ΛνΣοΫ
 2. ߋ৽͕͋Ε͹ඞཁͳ߲໨Λߋ৽͢Δ
 3. શͯͷσʔλͷߋ৽͕׬ྃͨ͠Βݺͼग़͠ݩʹ໭͢

Slide 55

Slide 55 text

RxJavaಋೖલ public class MigrateMasterDataTask extends AsyncTask { @Override
 protected Boolean doInBackground(Void... params) { final FrilService frilService = FrilServiceCreator.createFrilService(context);
 
 //ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ͔νΣοΫ
 Call call = frilService.checkNeedDatabaseUpdateSync(
 AppPrefs.getBrandVersion(context),
 AppPrefs.getBankVersion(context));
 
 DatabaseUpdate databaseUpdate = call.execute().body();
 if (databaseUpdate == null) {
 return false;
 }
 
 // ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ
 boolean updateBrand = databaseUpdate.isNeedForBrand();
 boolean updateBank = databaseUpdate.isNeedForBank();
 
 if (!updateBrand && !updateBank) {
 return true;
 }
 
 //ϦϞʔτͷσʔλΛ SQLite ʹҠߦ
 return syncFromRemote(updateBrand, updateBank); } }

Slide 56

Slide 56 text

RxJavaಋೖલ public class MigrateMasterDataTask extends AsyncTask { @Override
 protected Boolean doInBackground(Void... params) { final FrilService frilService = FrilServiceCreator.createFrilService(context);
 
 //ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ͔νΣοΫ
 Call call = frilService.checkNeedDatabaseUpdateSync(
 AppPrefs.getBrandVersion(context),
 AppPrefs.getBankVersion(context));
 
 DatabaseUpdate databaseUpdate = call.execute().body();
 if (databaseUpdate == null) {
 return false;
 }
 
 // ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ
 boolean updateBrand = databaseUpdate.isNeedForBrand();
 boolean updateBank = databaseUpdate.isNeedForBank();
 
 if (!updateBrand && !updateBank) {
 return true;
 }
 
 //ϦϞʔτͷσʔλΛ SQLite ʹҠߦ
 return syncFromRemote(updateBrand, updateBank); } }

Slide 57

Slide 57 text

RxJavaಋೖલ public class MigrateMasterDataTask extends AsyncTask { @Override
 protected Boolean doInBackground(Void... params) { final FrilService frilService = FrilServiceCreator.createFrilService(context);
 
 //ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ͔νΣοΫ
 Call call = frilService.checkNeedDatabaseUpdateSync(
 AppPrefs.getBrandVersion(context),
 AppPrefs.getBankVersion(context));
 
 DatabaseUpdate databaseUpdate = call.execute().body();
 if (databaseUpdate == null) {
 return false;
 }
 
 // ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ
 boolean updateBrand = databaseUpdate.isNeedForBrand();
 boolean updateBank = databaseUpdate.isNeedForBank();
 
 if (!updateBrand && !updateBank) {
 return true;
 }
 
 //ϦϞʔτͷσʔλΛ SQLite ʹҠߦ
 return syncFromRemote(updateBrand, updateBank); } }

Slide 58

Slide 58 text

RxJavaಋೖલ private boolean syncFromRemote(boolean isNeedUpdateBrand, boolean isNeedUpdateBank) { if (isNeedUpdateBrand) { // ωοτϫʔΫ͔ΒϒϥϯυϚελΛಉظऔಘ } if (isNeedUpdateBank) { // ωοτϫʔΫ͔ΒۜߦϚελΛಉظऔಘ } if (brandVersion != null) { // ΞϓϦ಺ʹ࠷৽ͷόʔδϣϯ৘ใΛอଘ } if (bankVersion != null) { // ΞϓϦ಺ʹ࠷৽ͷόʔδϣϯ৘ใΛอଘ } return true; }

Slide 59

Slide 59 text

ॲཧͷྲྀΕ͕௥͍ͮΒ͍ https://www.flickr.com/photos/eughenes/3758142701

Slide 60

Slide 60 text

RxJavaͷಋೖ

Slide 61

Slide 61 text

RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);
 final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);

Slide 62

Slide 62 text

RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);
 final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);

Slide 63

Slide 63 text

RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);
 final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);

Slide 64

Slide 64 text

RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);
 final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);

Slide 65

Slide 65 text

RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);
 final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);

Slide 66

Slide 66 text

RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);
 final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);

Slide 67

Slide 67 text

RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);
 final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

ωοτϫʔΫϨΠϠͷ੔උʹΑ ΓɺॲཧͷྲྀΕ͕Θ͔Γ΍͘͢ ͳͬͨ

Slide 70

Slide 70 text

RetrofitʹΑΓΤϯυϙΠϯτఆ ٛͷίʔυ͕গͳ͘ͳͬͨ

Slide 71

Slide 71 text

ΞʔΩςΫνϟ΍υΩϡϝϯτ ͷ੔උ͕νʔϜͷ։ൃ଎౓ʹӨ ڹ͢Δ

Slide 72

Slide 72 text

͜͜·Ͱ͕ϑϦϧAndroid൛ ͷي੻

Slide 73

Slide 73 text

• ϑϦϧAndroid൛ͷي੻ • ϑϦϧʹ͓͚Δ։ൃ • νʔϜ։ൃΛ͏·͘ճͨ͢Ίʹ΍͖ͬͯͨ͜ ͱɺ΍ͬͯྑ͔ͬͨ͜ͱ ΞδΣϯμ

Slide 74

Slide 74 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε࡞ۀ • ਺ࣈͷܭଌ

Slide 75

Slide 75 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε࡞ۀ • ਺ࣈͷܭଌ

Slide 76

Slide 76 text

Issue؅ཧ • LabelΛ׆༻ • ready͸ίʔυϨϏϡʔ ͯ͠OK

Slide 77

Slide 77 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε • ਺ࣈͷܭଌ

Slide 78

Slide 78 text

ϓϧϦΫΤετ • GitHubͷςϯϓϨʔτΛ׆༻ • ֬ೝखॱ͕ॏཁ

Slide 79

Slide 79 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε • ਺ࣈͷܭଌ

Slide 80

Slide 80 text

ίʔσΟϯάن໿ͱυΩϡϝϯτͷ੔උ • ίʔσΟϯάن໿ΛఆΊ͍ͯ·͢ • CONTRIBUTING.md • ϓϧϦΫΤετΛग़͢ࡍʹϦϯΫ͕දࣔ͞ ΕΔ

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

جຊతʹCookpadͷ ίʔσΟϯάن໿ʹ४ڌ͢Δ

Slide 83

Slide 83 text

https://github.com/cookpad/styleguide

Slide 84

Slide 84 text

ࡉ͔͍ͱ͜ΖͰ໎Θͳ͍Α͏ ʹίʔσΟϯάن໿Λ੔උ

Slide 85

Slide 85 text

READMEͷ੔උ

Slide 86

Slide 86 text

JavaDocͷ੔උ

Slide 87

Slide 87 text

JavaDocͷ੔උ

Slide 88

Slide 88 text

@colorͷ੔උ

Slide 89

Slide 89 text

@colorͷ੔උ

Slide 90

Slide 90 text

AnnotationΛੵۃతʹ࢖͏ dependencies { compile 'com.android.support:support-annotations:24.2.0' } void setActionBarAlpha(@IntRange(from = 0x0, to = 0xFF) int alpha) {

Slide 91

Slide 91 text

AnnotationΛੵۃతʹ࢖͏

Slide 92

Slide 92 text

https://developer.android.com/studio/write/ annotations.html Improve Code Inspection with Annotations

Slide 93

Slide 93 text

ϝϯςφϯε͠΍͍͢ঢ়ଶʹ ͓ͯ͘͠

Slide 94

Slide 94 text

։ൃ͕εϜʔζʹਐΈग़͢ͱ ى͖Δͷ͕

Slide 95

Slide 95 text

ϓϧϦΫΤετཷ·Δ໰୊

Slide 96

Slide 96 text

ϓϧϦΫΤετཷ·Δ໰୊ • ཷ·͍ͬͯΔϓϧϦΫΤετΛSlackʹ௨஌ • ϨϏϡʔ͠ͳ͍ͱຖ೔ͲΜͲΜ૿͍͑ͯ͘

Slide 97

Slide 97 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε • ਺ࣈͷܭଌ

Slide 98

Slide 98 text

CI

Slide 99

Slide 99 text

http://in.fablic.co.jp/entry/circle-ci-in-android-project

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

ϕʔλ൛ͷࣾ಺഑෍ • Fabric betaͰࣾ಺Ϣʔβʔʹ഑෍ • developϒϥϯνʹmerge͞ΕΔ౓ʹ࠷৽൛͕ ഑෍͞ΕΔ

Slide 102

Slide 102 text

Fabric betaʹΑΔβ൛഑෍ webhook push

Slide 103

Slide 103 text

ϦϦʔε൛ͱ͸ผΞϓϦͱͯ͠഑෍

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε • ਺ࣈͷܭଌ

Slide 106

Slide 106 text

ϢʔβʔΠϯλϏϡʔ

Slide 107

Slide 107 text

ϢʔβʔΠϯλϏϡʔ • iOS൛ϦϦʔεͷࡍʹ͸100ਓ͘Β͍Ϣʔβʔ Λั·͑ͯΠϯλϏϡʔΛ࣮ࢪ • ϑϦϧ͸Ϣʔβʔʹฉ͘จԽ

Slide 108

Slide 108 text

ϢʔβʔΠϯλϏϡʔ • ຖճͰ͸ͳ͍͕େ͖ͳϦχϡʔΞϧͳͲͷࡍ ͸ߦ͏ • ࣾ಺ͷCSελοϑ͸શһϑϦϧϢʔβʔͷͨ Ίɺ͙͢ʹΠϯλϏϡʔ͕Մೳ • ελϯσΟϯάσεΫͰΧδϡΞϧʹΠϯλ Ϗϡʔ

Slide 109

Slide 109 text

ϢʔβʔΠϯλϏϡʔ • QAલޙʹΠϯλϏϡʔΛͨ͠Γ΋͢Δ • ΠϯλϏϡʔͷ݁Ռɺ࢓༷Λม͑Δ͜ͱ΋͋ Δ • ੈʹग़Δલʹ࣮ࡍͷϢʔβʔͷ੠͕ฉ͚Δͨ ΊΤϯδχΞͱͯ͠΋҆৺

Slide 110

Slide 110 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε • ਺ࣈͷܭଌ

Slide 111

Slide 111 text

QA • ΤϯδχΞɺCSελοϑɺσβΠφʔɺϓϩμΫ τΦʔφʔ͕ࢀՃ • ςετγʔτΛࣄલʹΤϯδχΞ͕࡞੒͠ɺ߲໨ ʹԊͬͯಈ࡞νΣοΫΛ͍ͯ͘͠ • ΞϓϦͷΫΦϦςΟνΣοΫ • ࢓༷֬ೝ΋݉Ͷ͍ͯΔ

Slide 112

Slide 112 text

ςετγʔτ

Slide 113

Slide 113 text

QAͷྲྀΕ ࣄલ४උ 1. git-pr-releaseͰϦϦʔεʹ޲͚ͯQA༻ͷϓϧϦΫΤετΛ࡞Δ 2. ΤϯδχΞ͕ϓϧϦΫΤετͷίϝϯτΛϕʔεʹQA։࢝·Ͱʹςετγʔτ Λهࡌ͢Δ 3. SlackͰQAΛґཔ ౰೔ 1. ςετͷ֓ཁΛઆ໌ 2. ςετγʔτʹ͕ͨͬͯ͠ςετΛ͍ͯ͘͠ 3. ؾ͍ͮͨ͜ͱ͕͋Ε͹શͯϝϞΛ࢒͢

Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε • ਺ࣈͷܭଌ

Slide 116

Slide 116 text

ϦϦʔε .git-pr-templateʹϦϦʔεखॱΛهࡌ

Slide 117

Slide 117 text

No content

Slide 118

Slide 118 text

ϑϦϧAndroid൛ͷ։ൃ • Issue؅ཧ • ϓϧϦΫΤετ • ίʔσΟϯάن໿ɺυΩϡϝϯτͷ੔උ • CI • ϢʔβʔΠϯλϏϡʔ • QA • ϦϦʔε • ਺ࣈͷܭଌ

Slide 119

Slide 119 text

ΞϓϦ಺Πϕϯτͷܭଌ https://www.flickr.com/photos/helenanormark/9421984744

Slide 120

Slide 120 text

ΞϓϦ಺Πϕϯτͷܭଌ • Google Analytics • Facebook Analytics • Fabric • Firebase→BigQuery • ޿ࠂSDK

Slide 121

Slide 121 text

ෳ਺ͷSDKΛೖΕ͍ͯΔཧ༝ • ֤αʔϏεʹΑͬͯݟ͑Δ΋ͷ͕ҧͬͨΓɺࢪ ࡦΛߟ͑ΔࡍʹݟΔ਺ࣈͷ֯౓͕ҧͬͨΓ͢Δ • Ұ͚ͭͩ਺஋͕ͣΕͨΓͯ͠΋ݕ஌͢Δ͜ͱ͕ Ͱ͖Δ • αʔϏε্ॏཁͳKPI͸ಠࣗͷ؅ཧը໘Λ࡞ͬ ͯ΢Υον

Slide 122

Slide 122 text

εΫϦʔϯΠϕϯτͷܭଌ • ΤϯδχΞͷख࡞ۀͰ֤Activityʹܭଌίʔυ ΛຒΊࠐΜͰ͍Δ • ͔ͭͯiOSͰػցతʹຒΊࠐΉ͜ͱΛ͕ͨ͠ɺ ूܭ݁Ռ͕ͪ͝Όͪ͝Όʹͳͬͯ͠·ͬͨ͜ ͱ͕͋ͬͨ

Slide 123

Slide 123 text

εΫϦʔϯΠϕϯτͷॏཁੑ • ػೳΛվળͨ͠Γɺ࢒͢ɺ࢒͞ͳ͍ͷٞ࿦Λ ͢Δͱ͖ͷࡐྉʹͳΔ • ਺ࣈΛϕʔεʹٞ࿦Λ͢Δ

Slide 124

Slide 124 text

• ϑϦϧAndroid൛ͷي੻ • ීஈͷ։ൃͷྲྀΕ • νʔϜ։ൃΛ͏·͘ճͨ͢Ίʹ΍ͬͯྑ͔ͬ ͨ͜ͱ ΞδΣϯμ

Slide 125

Slide 125 text

໨తผνʔϜԽ

Slide 126

Slide 126 text

~2015೥ࠒ·Ͱ • iOSνʔϜɺAndroidνʔϜɺServerνʔϜɺ σβΠφʔͷΑ͏ͳઐ໳৬ͰΘ͔Ε͍ͯͨ iOS Android Server ♂♂♂ Design ♂♂♂ ♂♂♂ ♂♂♂

Slide 127

Slide 127 text

৽ػೳ΋௥Ճ͍͚ͨ͠Ͳɺ
 Android MରԠ͠ͳ͍ͱ…

Slide 128

Slide 128 text

2015೥ࠒ~ • AνʔϜɺBνʔϜͱ͍͏໨తผͷνʔϜʹશͯͷ։ൃϝϯόʔ͕ ॴଐ • ҕһձ੍ • ΫϥΠΞϯτҕһձ • αʔόʔҕһձ • σβΠϯҕһձ • ෼ੳҕһձ

Slide 129

Slide 129 text

໨తผνʔϜ B A ♂♂♂♂ ♂ ♂♂♂ ♂ ♂ ♂♂♂♂ ♂ ♂♂♂ ♂ ♂♂♂ ♂♂ iOS Android Server Design

Slide 130

Slide 130 text

໨తผνʔϜԽ • KPIผͷνʔϜʹͨ͜͠ͱͰ໨ඪ͕໌֬ʹͳͬ ͨ • Android͚ͩͱ͔Ͱ͸ͳ͘ɺ໨ඪΛୡ੒͢Δ ͨΊʹ෯޿͍εΩϧΛٻΊΒΕΔΑ͏ʹͳͬ ͨ

Slide 131

Slide 131 text

໨తผνʔϜԽ • ٕज़త՝୊ͳͲΛҕһձ͕੹೚Λ࣋ͭ͜ͱͰɺ ੹೚ൣғ͕ΑΓ໌֬ʹ • ྫʣAndroid 6.0ରԠɺRailsΞοϓσʔτ

Slide 132

Slide 132 text

αϙʔτରԠͷ౰൪੍ • CS͔Β࣭໰ͳͲ͕͋ͬͨΒΘ͔Δਓ͕౴͍͑ͯͨ • 2016೥ΑΓσΠϦʔͷ౰൪੍Λಋೖ • ຖேbot͕2໊બͼɺબ͹Εͨਓ͸ͦͷ೔Ұ೔αϙʔτ͔Β ͷ࣭໰ʹ౴͑Δ • Θ͔Βͳ͍৔߹͸Θ͔ΔਓʹΤεΫϩʔ • ରԠ಺༰͸Ͱ͖ΔݶΓwikiʹ࢒͢

Slide 133

Slide 133 text

αϙʔτରԠͷ౰൪੍ • ஌ࣝͷଐਓԽ͕ݮͬͨ • αʔϏε࢓༷ͷཧղ͕ਂ·ͬͨ • ྫ͑͹औҾपΓͷ࢓༷ͳͲ

Slide 134

Slide 134 text

ϦϦʔεϊʔτΛΤϯδχΞ͕ॻ͘

Slide 135

Slide 135 text

ϦϦʔεϊʔτΛΤϯδχΞ͕ॻ͘ • ࣮૷Λ୲౰ͨ͠ΤϯδχΞΛத৺ͱͯ͠ϦϦʔ εϊʔτΛॻ͘ • ਓؒຯͷ͋Δจষ • ࠷ऴతʹϥΠςΟϯάελοϑʹϨϏϡʔ͠ ͯ΋Β͏

Slide 136

Slide 136 text

PlayετΞͷϨϏϡʔ • AppFollowͱ͍͏αʔϏεΛಋೖ

Slide 137

Slide 137 text

No content

Slide 138

Slide 138 text

No content

Slide 139

Slide 139 text

PlayετΞͷϨϏϡʔ • Slackͷνϟϯωϧʹਵ࣌ඈΜͰ͘Δ • ωΨςΟϒͳϨϏϡʔ͕͋Ε͹։ൃɺCSνʔϜ͕ रͬͯվળʹ໾ཱͯΔ • CSνʔϜ಺ʹϨϏϡʔʹฦ৴͢Δ୲౰Λஔ͍͍ͯΔ • ΞϓϦͷධՁΛྑ͍ঢ়ଶʹอͭ

Slide 140

Slide 140 text

Slide 141

Slide 141 text

·ͱΊ

Slide 142

Slide 142 text

௕͘ଓ͘ΞϓϦΛ։ൃ͠ଓ͚Δ ʹ͸ • ఆظతʹΞʔΩςΫνϟΛݟ௚͢ • ن໿΍υΩϡϝϯτΛ੔උ͢Δ • ૝૾Ͱ͸ͳ͘ɺQA΍ϢʔβʔΠϯλϏϡʔͳ ͲͰ࣮ࡍͷϢʔβʔͷ੠Λฉ͖ɺαʔϏεʹ ൓ө͢Δ

Slide 143

Slide 143 text

͝੩ௌ͋Γ͕ͱ͏ ͍͟͝·ͨ͠