Slide 1

Slide 1 text

J2ObjCを使ってJava資産 をiOS開発で使ってみた @uakihir0

Slide 2

Slide 2 text

自己紹介 ● Akihiro Urushihara (うるし) ● @uakihir0 ● 制作物 ○ TheWorld ○ SocialHub

Slide 3

Slide 3 text

J2ObjC?

Slide 4

Slide 4 text

J2ObjC ● Java → Objective-C トランスレータ ● 2012年に Google から公開 ● まあまあつらい

Slide 5

Slide 5 text

J2ObjC の採用理由は?

Slide 6

Slide 6 text

J2ObjC の採用理由は? → 要件的に満たすものが J2ObjC だけだった

Slide 7

Slide 7 text

SocialHub

Slide 8

Slide 8 text

SocialHub ● iOS/Android 向けのマルチ SNS クライアントアプリ ○ SNS 周りのロジックは共通のものを使用したい ■ できる限り既存 OSS ライブラリを用いて楽したい

Slide 9

Slide 9 text

SocialHub ● SNS の抽象化 ○ ライブラリに実装における複雑 性を押し込む

Slide 10

Slide 10 text

SocialHub ● iOS/Android 向けのマルチ SNS クライアントアプリ ○ SNS 周りのロジックは共通のものを使用したい ■ できる限り既存 OSS ライブラリを用いて楽したい ○ 普段使いするアプリを目指すので UI/UX 妥協しない

Slide 11

Slide 11 text

SocialHub ● iOS/Android 向けのマルチ SNS クライアントアプリ ○ SNS 周りのロジックは共通のものを使用したい ■ できる限り既存 OSS ライブラリを用いて楽したい ○ 普段使いするアプリを目指すので UI/UX 妥協しない ライブラリは共有し、UI は OS 毎にネイティブで書きたい!

Slide 12

Slide 12 text

採用候補

Slide 13

Slide 13 text

Embeddinator-4000 ● .NET ライブラリを他言語で使用可能にするプロジェクト ○ Xamarin のサブプロジェクト ○ iOS 向けに Objective-C に変換する機能がある ■ ジェネリクスが使えない (#232) 制限がありこれが致命的

Slide 14

Slide 14 text

Kotlin/Native ● Kotlinを他言語/環境で使用可能にするプロジェクト ○ 検討時の 2018 初頭では v0.6 ぐらいで知見がほぼ皆無 ○ 既存 OSS ライブラリの利用ができない

Slide 15

Slide 15 text

J2ObjC ● Java → Objective-C トランスレータ ○ Java の既存 OSS ライブラリが使用可能! ○ Kotlin/Native にも鞍替えがギリギリ可能! ○ 知見は国内にはほぼ無い!

Slide 16

Slide 16 text

フレームワーク類 ● UI はネイティブで追求したいので今回は検討外 ○ Xamarin.Forms ○ Flutter ○ React Native ○ Ionic

Slide 17

Slide 17 text

J2ObjC Translation

Slide 18

Slide 18 text

Hello World ● Java コードを準備 ● Objective-C へ変換 public class Main { public static void main(String[] args) { System.out.println("Hello World"); } } $ j2objc Main.java Java

Slide 19

Slide 19 text

#include "IOSObjectArray.h" #include "J2ObjC_source.h" #include "Main.h" #include "java/io/PrintStream.h" #include "java/lang/System.h" @implementation Main - (instancetype)init { Main_init(self); return self; } + (void)mainWithNSStringArray:(IOSObjectArray *)args { Main_mainWithNSStringArray_(args); } // リフレクション等ためのメタデータ情報 + (const J2ObjcClassInfo *)__metadata { /* ... */ } @end void Main_init(Main *self) { /* ... */ } Main *new_Main_init() { /* ... */ } Main *create_Main_init() { /* ... */ } void Main_mainWithNSStringArray_(IOSObjectArray *args) { Main_initialize(); [((JavaIoPrintStream *) nil_chk(JreLoadStatic(JavaLangSystem, out))) printlnWithNSString:@"Hello World"]; } Objective-C (.m)

Slide 20

Slide 20 text

例外 ● Objective-C のレイヤーで対処 @try { /* ... */ } @catch (JavaLangThrowable *throwable) { /* ... */ } Objective-C (.m)

Slide 21

Slide 21 text

J2ObjC Annotations ● コード変換の所々の問題についてのアプローチ

Slide 22

Slide 22 text

弱参照 ● @Weak @Property 等を付与してメモリリークを回避 public class Main { @Weak private Runnable callback; Java @interface Main () { @public __unsafe_unretained id callback_; } Objective-C (.m)

Slide 23

Slide 23 text

弱参照 ● @Weak @Property 等を付与してメモリリークを回避 public class Main { @Property("weak, nonatomic") protected Runnable callback; Java @interface Main : NSObject { @public __unsafe_unretained id callback_; } @property (weak, nonatomic) id callback; Objective-C (.h)

Slide 24

Slide 24 text

関数名 ● デフォルトでは型名が関数名に付与される public void setDate(int year, int month, int day){ /* … */ } Java - (void)setDateWithInt:(jint)year withInt:(jint)month withInt:(jint)day { Objective-C (.m)

Slide 25

Slide 25 text

関数名 ● @ObjectiveCName を付与して指定 @ObjectiveCName("setDateWithYear:month:day:") public void setDate(int year, int month, int day){ /* … */ } Java - (void)setDateWithYear:(jint)year month:(jint)month day:(jint)day { Objective-C (.m)

Slide 26

Slide 26 text

Nullability ● @Nonnull @Nullable (jsr305) を付与して Nullability を明示 public class Main { public void greeting(@Nonnull String name){ /* ... */ } Java - (void)greetingWithNSString:(NSString * __nonnull)name; Objective-C (.h)

Slide 27

Slide 27 text

Development

Slide 28

Slide 28 text

ビルドツールの選択 ● make ● bazel ● plugins ○ maven-plugin ○ gradle-plugin

Slide 29

Slide 29 text

gradle-plugin (j2objc-contrib/j2objc-gradle) ● 面倒なことを色々やってくれるので非常に有用 ○ ライブラリの依存関係の解決 ○ 標準ライブラリへのリンク ○ 各ターゲット向けのビルド ○ Podfile の作成

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

gradle-plugin (uakihir0/j2objc-gradle) ● 問題のあった箇所を修正して公開中 ○ Gradle 4.x に対応 ■ 2.x から修正 ○ 静的ライブラリの作成方法を変更 ■ ar → libtool に変更 (コマンド長の問題に対応)

Slide 32

Slide 32 text

CI/CD ● 開発初期は手元の MacBookPro でビルドしていた ○ 30分ぐらいかかり半分近くバッテリーが消える ■ しかもビルド中重くて何も出来ない

Slide 33

Slide 33 text

CI/CD ● Travis CI を使用し始める ○ ビルド回数を気にせず Mac OS 環境が使える ○ ビルド時間が 50 分までの制限がある

Slide 34

Slide 34 text

CI/CD ● GitHub Actions に変更 ● Debug/Release ビルドを並列に実行

Slide 35

Slide 35 text

Other Problems ● HmacSHA1 の暗号化ができない問題 ○ USの暗号化輸出規制の問題? 再実装して対応 ● Java のクラスの動的読み込み問題 ○ Class.forName(“...”) で文字列からクラスを作成される問題 ○ 生成されそうなクラスは別途コンパイル対象に指定

Slide 36

Slide 36 text

Release ● iOS 版リリース ○ 70MB 程で意外とコンパクト ○ パフォーマンスは問題ない ○ 共通ライブラリは公開中 ■ uakihir0/SocialHub

Slide 37

Slide 37 text

総括

Slide 38

Slide 38 text

BAD ● 導入障壁が高い ● 知見が少なくトラブルシュートが難しい ● 開発サイクルがやや遅くなる

Slide 39

Slide 39 text

GOOD ● クリーンアーキテクチャに必然的になる ● パフォーマンス劣化がほぼ無い ● 共通コードで実装量を減らせる!

Slide 40

Slide 40 text

Questions?