Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android + JSON-RPC

E77b6a5f919f7366d94f21eee9a014f5?s=47 operandoOS
September 16, 2016

Android + JSON-RPC

Android + JSON-RPC

shibuya.apk #10
http://shibuya-apk.connpass.com/event/39433/

E77b6a5f919f7366d94f21eee9a014f5?s=128

operandoOS

September 16, 2016
Tweet

More Decks by operandoOS

Other Decks in Technology

Transcript

  1. Android + JSON-RPC shibuya.apk #10

  2. About Me Shinobu Okano @operandoOS Mercari, Inc. Souzoh, Inc.

  3. None
  4. shinobu.apk #3 ΍Γ·͢ʂʂ

  5. Androidʹ͍ͭͯޠΔ! shinobu.apk #1 Λ։࠵͠·ͨ͠ʂ http://tech.mercari.com/entry/2016/02/12/122918

  6. shinobu.apk #2 ͷύωϧσΟεΧογϣϯ ࿥ԻσʔλͱShow NotesΛެ։͠·ͨ͠ʂ http://hack-it-iron.hatenablog.com/entry/ 2016/04/20/124823

  7. http://shinobu-apk.connpass.com/event/40202/ Join!! shinobu.apk #3

  8. JSON-RPC??

  9. JSON-RPC “JSON-RPC is a stateless, light-weight remote procedure call (RPC)

    protocol.”
  10. JSON-RPC spec http://www.jsonrpc.org/specification

  11. RPC • gRPC • http://www.grpc.io/ • Go Conference 2016 SpringͰgRPCͷݱঢ়ʹ͍ͭͯ

    ൃද͖ͯ͠·ͨ͠ • http://tech.mercari.com/entry/ 2016/04/27/145227
  12. JSON-RPC 2.0

  13. JSON-RPC HTTP bodyͷJSONͰϦΫΤετΛهड़͢Δ

  14. JSON-RPC Request { "jsonrpc": "2.0", "method": "subtract", "params": [ 42,

    23 ], "id": 1 }
  15. JSON-RPC Response { "jsonrpc": "2.0", "result": 19, "id": 1 }

  16. JSON-RPC Batch 1ճͷ௨৴Ͱෳ਺ͷϦΫΤετΛૹΕΔ

  17. JSON-RPC Request [ { "id": 1, "jsonrpc": "2.0", "method": "shibuya.apk",

    "params": { ... } }, { "id": 2, "jsonrpc": "2.0", "method": "shinobu.apk", "params": { ... } } ]
  18. JSON-RPC Response [ { "id": 1, "jsonrpc": "2.0", "result": {

    ... } }, { "id": 2, "jsonrpc": "2.0", "result": { ... } } ]
  19. Կʹ࢖͏ͷ??

  20. Կʹ࢖͏ͷ??

  21. Կʹ࢖͏ͷ?? • λΠϜϥΠϯͷ౤ߘΛऔಘ • ݱࡏ஍ͷ࠲ඪΛॅॴʹม׵͢Δ • όφʔΛऔಘ͢Δ ҎԼͷϦΫΤετ͕1ճͷϦΫΤετͰͰ͖Δ

  22. GET /home??

  23. ෳ਺ͷॲཧΛ·ͱΊͨAPI͸ ࢓༷͕յΕ΍͍͢

  24. JSON-RPC Batch • API͸ݸʑͷॲཧΛϝιουͱͯ͠ఆٛ • ΫϥΠΞϯτଆͰݸʑͷॲཧΛ1ͭͷ
 ϦΫΤετʹ·ͱΊͯݺͼग़͢

  25. JSON-RPC Request [ { "id": 1, "jsonrpc": "2.0", "method": "GetTimeline",

    "params": { ... } }, { "id": 2, "jsonrpc": "2.0", "method": "GetBanner", "params": { ... } } ]
  26. JSON-RPC Response [ { "id": 1, "jsonrpc": "2.0", "result": {

    ... } }, { "id": 2, "jsonrpc": "2.0", "result": { ... } } ]
  27. Αͦ͞͏!!

  28. ͡ΌAndroidͰ࣮૷͢Δ͔!!

  29. OkHttp࢖ͬͯॻ͍ͯΈΔ Request OkHttpClient client; JSONObject json = new JSONObject(); JsonArray

    params = new JsonArray(); json.put("method","subtract"); params.put(42); params.put(23); json.put("params",params); RequestBody requestBody = RequestBody.create(MEDIA_TYPE, json.toString().getBytes()); Request request = new Request.Builder() .url("https://....") .post(requestBody) .build(); Response response = client.newCall(request).execute();
  30. OkHttp࢖ͬͯॻ͍ͯΈΔ Response Response response = client.newCall(request).execute(); // ... isSuccessfulͷνΣοΫͱ͔... ResponseBody

    value = response.body(); JSONObject j = new JSONObject(value.string()); int result = j.getInt("result");// return 19
  31. ͜ΕΠέͯ·͔͢Ͷʁʁ

  32. Πέͯͳ͍Ͱ͢ΑͶ...

  33. ͍͍ײ͡ͷLibrary͋ΔΜ͡ΌͶ… ݕࡧݕࡧ

  34. ͋·Γͳ͍?? • jsonrpc4j • https://github.com/briandilley/jsonrpc4j • BatchʹରԠͯ͠ͳ͍?? • retrofit-jsonrpc •

    https://github.com/segmentio/retrofit-jsonrpc • BatchʹରԠͯ͠ͳ͍??
  35. ్ํʹ฻ΕΔ೔ʑ...

  36. ͋ʔͳΜͰ͜ΜͳAPIʹ ͳͬͯΔΜͩ...

  37. ͏͎…๻͸ΘΔ͘ͳ͍... (ɻ-ω-)

  38. ͦ͏΋ݴͬͯΒΕͳ͍...

  39. ͦ͏ͩʂ ࣗ෼Ͱ࡞Ε͹͍͍Μͩʂ

  40. ࡞ͬͯΈͨ ※౰೔·Ͱʹίʔυ͕ެ։Ͱ͖·ͤΜͰͨ͠
 ͍͢·ͤΜ

  41. ࡞Δલʹߟ͑ͨ͜ͱ • ຖճಉ͡ॲཧ͸ॻ͖ͨ͘ͳ͍ • ϦΫΤετͷܕ͕ܾ·Ε͹Ϩεϙϯεͷܕ͕ܾ·Δ • ϦΫΤετͱϨεϙϯεΛܕͰఆٛ • Batch ϦΫΤετΛ͍͍ײ͡ʹड͚औΓ͍ͨ

    • Rxͱ͔࢖ͬͪΌ͏ʁʁ • ಛఆͷ௨৴ϥΠϒϥϦʹґଘ͠ͳ͍
  42. JSON-RPCͷΫϥΠΞϯτ࣮૷Ͱେมͩͬͨ͜ͱ • Batch ϦΫΤετͷड͚औΓํ • ΤϥʔϋϯυϦϯά • RetrofitͷԸܙ͕ड͚ΒΕͳ͍…

  43. Ϩεϙϯεͷύλʔϯ • OK 1ͭͷϨεϙϯε • OK ෳ਺ͷϨεϙϯε(2,3ͭ) • NG શϨεϙϯεΤϥʔ

    • NG Ұ෦ͷϨεϙϯεΤϥʔ
  44. Batch ϦΫΤετͷड͚औΓํ • ෳ਺ͷϦΫΤετΛ࡞Δ • ࡞ͬͨϦΫΤετΛ·ͱΊͯAPIʹ౤͛Δ • ෳ਺ͷϨεϙϯε͕ฦͬͯ͘Δ • ϋϯυϦϯάͯ͠ϨεϙϯεΛ௨஌͢Δ

  45. ෳ਺ͷϨεϙϯε...??

  46. ෳ਺ͷϨεϙϯε...?? • List<Object> ?? • List<?> ?? • List<JSONObject> ??

  47. ͲΕ΋Πέͯͳ͍

  48. ͦ͏ͩ...Tupleͩʂʂ

  49. None
  50. ے೑ 2ͭ @Getter public class Pair<F, S> { private final

    F first; private final S second; private Pair(F first, S second) { this.first = first; this.second = second; } public static <F, S> Pair<F, S> create(F first, S second) { return new Pair<>(first, second); } }
  51. ے೑ 3ͭ @Getter public class Triplet<F, S, T> { private

    final F first; private final S second; private final T thread; private Triplet(F first, S second, T thread) { this.first = first; this.second = second; this.thread = thread; } public static <F, S, T> Triplet<F, S, T> create(F first, S second, T thread) { return new Triplet<>(first, second, thread); } }
  52. ෳ਺ͷϦΫΤετΛ࡞Δ // ϦΫΤετͱϨεϙϯεΛΫϥεͱͯ͠ఆٛ // ϦΫΤετ : GetBanner Ϩεϙϯε : GetBanner

    class GetBannerResponse { String url; } // ϦΫΤετͷܕ͕ܾ·Ε͹Ϩεϙϯεͷܕ͕ܾ·Δ = RequestType<Ϩεϙϯεͷܕ> class GetBanner extends RequestType<GetBannerResponse> { @Override public String getMethod() { return "GetBanner"; } @Override protected Class<GetBannerResponse> getResponseType() { return GetBannerResponse.class; } }
  53. ෳ਺ͷϦΫΤετΛ࡞Δ // ಉ͡Α͏ʹผAPIͷϦΫΤετͱϨεϙϯεΛΫϥεͱͯ͠ఆٛ // ϦΫΤετ : GetTimeline Ϩεϙϯε : GetTimelineResponse

    class GetTimelineResponse { List<Item> items; } class GetTimeline extends RequestType<GetTimelineResponse> { private final long timelineId; GetTimeline(long timelineId) { this.timelineId = timelineId; } @Override public String getMethod() { return "GetTimeline"; } @Override protected Class<GetTimelineResponse> getResponseType() { return GetTimelineResponse.class; } }
  54. ࡞ͬͨϦΫΤετΛ·ͱΊͯAPIʹ౤͛Δ GetTimeline getTimeline = new GetTimeline(1); GetBanner getBanner = new

    GetBanner(); RxApiClient rxApiClient = new RxApiClient(); // Observable<Pair<GetBannerResponse, GetTimelineResponse>> ͕ฦͬͯ͘Δ rxApiClient.responseFrom(getTimeline,getBanner) ....
  55. ϦΫΤετͷΫϥε͸JSONʹͳͬͯ HTTP bodyʹઃఆ͞ΕΔ [ { "params": { "timelineId": 1 },

    "method": "GetTimeline", "jsonrpc": "2.0", "id": "1" }, { "params": {}, "method": "GetBanner", "jsonrpc": "2.0", "id": "2" } ]
  56. ෳ਺ͷϨεϙϯε͕ฦͬͯ͘Δ + 
 ϋϯυϦϯάͯ͠ϨεϙϯεΛ௨஌͢Δ // ෳ਺ͷϨεϙϯεTupleʹแΜͰRxʹྲྀ͢ // responseFrom಺ͰTupleʹแΉॲཧΛͯ͠Δ rxApiClient.responseFrom(getTimeline, getBanner)

    .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Pair<GetTimelineResponse, GetBannerResponse>>() { @Override public void call(Pair<GetTimelineResponse, GetBannerResponse> pair) { // Tuple͔ΒϨεϙϯεΛऔΓग़͢ pair.getFirst(); // return GetTimelineResponse pair.getSecond(); // retrun GetBannerResponse } });
  57. Thanks!