urushi blog

プログラマでゲーマーのうるしが綴るメモ

Java のコードを Objective-C に? J2ObjC を試してみた。

前回の記事に引き続き、クロスコンパイル関連の記事になります。前回の記事では Embeddinator-4000 を紹介しました。

結論

今回もまずは結論から記載すると、今回の J2ObjCギリギリ使えそうな感じでした。自分の目的であるクロスプラットフォームで、同一のコードのネットワークライブラリを作るという目的をなんとか達成できるポテンシャルがあると思っています。

動機

前回の Embeddinator-4000iOS 向けの Objective-C コード生成においてジェネリクスが用いることができないという、非常に大きな欠点を抱えており、解決にはまだ時間がかかりそう (本当に解決するかも不明) なので、クロスプラットフォーム向けのコード生成機能が他にもないかを探していたところ、見つけたのがこの J2ObjC でした。

J2ObjC とは?

ざっくり言えば、Java のコードを Objective-C に変換するツールです。Embeddinator-4000 はざっくり言えば、ランタイムを乗っけてその上で動かしてしまえ、というちょっと雑な手法でしたが、J2ObjC は真面目に Java のコードをガッツリ Objective-C に変換します。言語仕様レベルの変換も非常に難しい問題ですが、一番面倒かつ重要になってくるのが、各種標準ライブラリの存在になります。 Java には非常に多くの標準ライブラリが備わっており、ネットワーク周りから計算ライブラリまで一通りのものは揃っています。 J2ObjC はそこが非常に大きな問題になっています。 J2ObjC では JavaJRE における標準ライブラリの Objective-C 実装を非常に広範囲で提供しており (その提供自体にも J2ObjC が用いられている箇所も少なくない) それを用いることで標準ライブラリを用いたコードも Objective-C に変換することが可能です。

開発者

J2ObjC の開発元は Google です。GoogleJavaPython の文化だと思うので、そこでその資源を活かして iOS macOS アプリを記述したかったのだと思います。 Objective-C に変換されたコード片にライブラリを付け足していく形でアプリを実現しているのだと思います。そのためか、コードの質も高くメンテも高頻度で行われています。

使用方法

J2ObjC を用いてざっくりコンパイルするのであれば、その公式サイトを参照してください。共有ライブラリ等を作成するのであれば、J2ObjCでJavaとSwiftを連携させる あたりの記事が詳しいです。

自分は Twitter4J を使ったライブラリを書きたいので、その依存関係を一緒に Objective-C に変換してくれるサポートがほしかったので、Gradle Plugin を用いたライブラリプロジェクトを作成しました。(Gradle Plugin は何故か開発が止まっているのですが、Maven Plugin よりは断然使いやすそうだったのでこちらを採用しました…)

使用感

ライブラリで使用しているライブラリも合わせて Objective-C に変換するためには、Maven レポジトリからソースコードを拾ってくる必要があります。基本的に Gradle Plugin がなんとかしてくれるので、特に意識する必要はないですが、そのためソースコードが提供されていないライブラリは使用できません。(Kotlin で書かれたコードも当然変換できない。(class に落としてデコンパイルとかすればいけるのかもしれないけど底までしたくない)) 自分の書いたコードはあっさり Objective-Cコンパイル完了。Twitter4J についてもあっさりコンパイル完了。意外とコンパイルに時間がかかると思っていたので、拍子抜けでした。

落とし穴

さて、Gradle Plugin は cocoapod 用の podspec ファイルを吐いてくれるので、それを参照すれば iOS のプロジェクトでも簡単に依存関係に追加することができます。(吐かれる podspec ファイルには色々足りないので、最新の cocoapod で用いるためには修正が必須) と思って追加してビルドしたらリンカエラーになってしまい、調べてみたらリンカフラグが足りなかった。(podspec の情報が足りない -> Gradle Plugin がメンテされていないことの影響)

そしていざ、iOSTwitter4J を実行してみたら、ClassNotFound のエラーで落ちた。調べてみると、Twitter4J にはあるクラスが何故か J2ObjCObjective-C に変換されていなかった。J2ObjC はオンデマンドにクラスを Objective-C に変換するため、どのクラスからも import されていないクラスは Objective-C に変換されない。そのため Class.forName()Java 内で動的にロードされたクラスについては、変換対象にならなかったので ClassNotFound になっていました。そのため、Class.forName() で動的ロードしていた部分を普通にインスタンスを生成するように変更しました。

その後に立ちはだかったのは、HmacSHA1 が使えないという問題。確かに変換後の Objective-CSecurity.getProviders() で取得した内容から、HmacSHA1 が使えないことは分かったんですが、じゃあ何故 JVM で提供されているものが使えないのか?という問題があるのですが、どうやら US の輸出規制の問題だとかで提供されていないようでした。ので、OpenJDK から HmacCore.java を移植し、ついでに MessageDigit.java のバグで、複数回ハッシュを生成した時に状態を持ち越してしまう問題 (MessageDigitIssue) があり、正しく HmacSHA1 が生成できない問題があったので、SHA1 を生成する毎に手動で状態をリセットするように変更。して、やっと Twitter にリクエストすることに成功しました。

そして最後に立ちはだかったのが、Accept-Encoding: gzip でリクエストしているのに、何故かレスポンスが Objective-C に変換後のコードだと gzip ではないとエラーを吐いてしまう事。これは帰ってきたライブラリを見てわかったのですが、Objective-C に変換後は HTTP リクエストを飛ばす際に、勝手に Accept-Encoding: gzip で勝手に送信して、レスポンスも勝手に gzip を紐解いてしまうという、ライブラリ間の挙動の差でした。ので、始めの2バイトを確認して、gzip であるかを判断して、その後の処理を分岐するように変更。そしてやっとレスポンスを得ることに成功しました。

依存関係がほぼない Twitter4J でもこれぐらいかかったので、他に追加でもしようものならもっと大変だろうと思います。ですがなんとか成功したので、もう少し頑張って iOS Android 共用ライブラリの夢をみようと思います。ついでに、 Twitter4J をフォークして J2ObjC で動作可能にしたものは uakihir0Twitter4J です。(Hmac の対応はここレポジトリにはありません) JitPack 等で使ってください。

結論

J2ObjC はモデルの共通化とか、外部ライブラリに依存しないコードなら検討の価値あり。外部ライブラリを頑張ろうとすると、そもそもソースコードがなかったりと地獄を見るが、なんとかぎりぎり頑張れる。

.NET のコードを他言語に変換? Embeddinator-4000 を使ってみた。

結論

先に所感から記載しておくと Embeddinator-4000 は「まだ実用的ではない」ものという結論になりました。実用ベースのものをお探しの人は参考になるものではないという認識のもと記事を読んでいただけると助かります。

動機

遊びでアプリを作りたい。公開も将来的にはしていきたい。その際に iOS, Android 両方で共有のライブラリを用いたい。しかし、UI 等はこだわりを持っていい感じに作成したいので、Xamarin.Forms のようなものでは不十分だし、ネイティブの有用なライブラリをがつがつと用いて、UX を上げたい。このような時に使える何かツールはないか? そこで Twitter 上で質問したところ、返ってきた答えに、 Embeddinator-4000 というものがあったので、GitHub から手探りで試してみました。

Embeddinator-4000 とは?

Xamarin のサブプロジェクトの一つで、.NET のライブラリを多言語に変換してマルチプラットフォーム上で用れるようにしたものです。GitHub に概要が記載されています。

Embeddinator-4000 の技術

認識間違いがあると思いますがご容赦ください

マルチプラットフォームで使えるというと、気になってくるのが技術面です。見たところによると、どうやら C にコード変換をした後に、各プラットフォーム向けにバインディングをしていくようです。Java (Android 向け) には JNI (Java Native Interface) を用いてデータの受け渡しを行い、 Objective-C (iOS 向け) には単に C の関数コールで C コードの実行を行っています。要するに、各言語毎に細かい実装があるわけではなく、基本的には C に落とし込まれているという認識です。また、C の実行に際して、ランタイム環境等を通して、実行時の抽象化された部分を上手く処理しています。

使用方法

基本的に以下のページを追っていくだけで何とかなります。(または GitHub の GetStarted を参照)

Xamarin .NET Embedding

C# .NET のライブラリを作成して、その依存関係に NuGet から Embeddinator-4000 を追加して、コマンドを打てばコンパイルできる! といいたいところだったのですが、現状 Android 向けのコンパイルは v0.3.0 ではエラーになってしまうので、GitHub のページから Clone してきて、Visual Studio でバイナリを作成する必要があります。

NuGet で取得してきてたフォルダ構成は、Embeddinator-4000 のコンパイルにおける最小構成になっています。Visual Studioコンパイルしたさいも、Embeddinator-4000.exe や objcgen.exe 以外にもサポートファイルが幾つも存在しているので、そこを参考にして移動してください。

使用感

各言語向けにコンパイルした後、Android プロジェクトなら aar を、iOS プロジェクトなら .framework を依存関係に追加すれば使用でき、Android からはそのまま Java だけでなく Kotlin のコードからも参照でき、iOS なら、Obective-C の bridging header を利用して Swift のコードから使用することができます。

Javaコンパイルした場合、パッケージ名 (名前空間) が存在しているため、C# のクラス名と一対一対応します。一方で、Objective-C にはそれに該当するものが存在しないため、クラス名が一対一対応しません。

namespace Service
{
    public class ActionClass {  ...  }
}

上記のようなクラスの場合、Servicre_ActionClass のような名前になります。要するにパッケージが深くなっていく度に、クラス名がどんどん長くなっていくので、実際に使用する際は型エイリアス (Swift) のようなものを用いて、短くして使用したいところです。

制限

特に iOS (Objective-C) ではサポートされていない機能が多く、そこが非常に大きなネックになっています。特に一番自分が触っていて感じた壁として、ジェネリクスがあります。C# におけるジェネリクスObjective-C におけるジェネリクスの差異があり、その吸収をランタイム環境で行っているっぽいのですが、iOS におけるアプリの規約上、ランタイム環境 (要は動的にプログラムを処理する機能) はアプリに含まれてはいけないという規定があります。そのため、iOS においてランタイム環境を含める事ができず、ジェネリクス対応が難しくなってしまっています。(GitHub における該当 issue) 参考:Xamarin における Generics について

自分は試しにライブラリに CoreTweet を追加したら、エラーになってしまい変換ができませんでした。このライブラリ自体は Xamarin.Native で扱えるはずのライブラリなので、もしかしたらいけるかな?と思っていましたが、やっぱり駄目でした。Objective-C についてはコンパイラが成熟してくれるのを暫く待たないと、まともに運用はできなさそうです。(C で吐くモードもあるのでそれを使えばいいじゃない、と思われるかもしれないですが、ランタイム環境が入ってくると思われるので、おそらく規約違反になって終了です) ( ドキュメントには記載はありませんが、Swift のコードコンパイルもできるみたいです。が、これもランタイム環境を同梱する形式のようなので、macOS にしか対応していません)

結論

Android についてはまだ自分の用途的にはなんとかなる部分もあるが、それであれば Java で書けばいいので、今のところ、Embeddinator-4000 を使用する意味は薄い。 (AndroidWindows ワールドを対象にしている方には意味があると思う) 一方で荒削りの部分も多いので、今後に期待が持てるプロジェクトだと思います。(ちゃんとメンテされていくのかはちょっと不明だけど、DroidKaigi 2018 にてコミッターの方がこんなセッションされるようなので、多分安心?)

おまけ:次のアクション

ジェネリクスを回避する策を試してみて無理そうなら、Embeddinator-4000 以外の別の方法を考える。自分のターゲットとしては iOS, Android なので、候補としては J2ObjC を考えている。(以前試したことがあったけど、かなりメンテされていていい感じになってそうな雰囲気を感じる?)

記事にいいねがいっぱい付いたら、失敗したサンプルプロジェクト上げます。(ライセンス的にもんだいなさそうなら、ビルドした Embeddinator-4000.exe とかも上げる)

BitZeny マイニングにおけるメモ

BitZeny

BitZeny とは仮想通貨の一種で、大きな特徴として、マイニングにおけるハッシュアルゴリズムが特殊で、 GPU を使用しても大きな速度向上が無く、CPU で計算するのが効率が良いとされています。そのため、 優秀なGPUを積んだPC等の初期投資が必要なく、余らせている PC でマイニングが可能で、比較的参入が容易です。

効率

正直効率はあまり良くないです。

www.coingecko.com

相場は安定しています。が、といって十分な効率かと言われれば微妙なところ。VPS 等を使うと、選んだ会社によりますが、若干の利益を あげることも可能です。しかし、CPU 使用率が高い水準で張り付くので、他の利用者に迷惑がかかり差し止められたりと、 最近問題になっていたりもします。僕は別の用途でつけっぱなしにしているPCがあるので、それの余剰リソースでマイニングさせてます。 電気代との効率とかは特に計算していませんが、それだけで一ヶ月で大凡 110 ZNY ぐらい得ることができました。 流石に電気代ぐらいはペイできているはず。

プールマイニング [宣伝]

始め方については色々な方が既に説明されているので、特に記載しません。マイニングは一般的にマイニングプールという、複数人協力してマイニングをし、その利益を分配し合うという方式を取る場合が一般的です。どこでもマイニングプールは同じやろと思われがちですが、実際マイニングプールには、高可用性が求められます。(マイニングが止まると辛いので)

そこで、知り合いのインフラエンジニアがガチで作ったマイニングプールがあるので紹介しておきます。僕もここでマイニングをしています。

Hoge Pool - Bitzeny Pool - Home

正直、ここ以外にも色々マイニングプールはあるので、色々探してみると BitZeny コミュニティーが分かってきて面白いかもしれません。

おまけ

最後に、CentOS6 で暇させてるサーバーがあったので、 マイニングさせた時のコマンドをメモしておきます。

#! /bin/sh
yum -y groupinstall "Development Tools"
wget http://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
wget http://rpms.famillecollet.com/enterprise/remi-release-5.rpm
rpm -Uvh epel-release-5*.rpm
rpm -Uvh remi-release-5*.rpm
yum -y install python-devel screen
yum --enablerepo=remi install libcurl-devel -y
mkdir /opt/miner
cd /opt/miner
wget https://github.com/macchky/cpuminer/archive/v2.5.0z.tar.gz --no-check-certificate
tar -zxvf v2.5.0z.tar.gz
cd cpuminer-2.5.0z/
sh autogen.sh
./configure CFLAGS="-O3"
make
make -j
mv minerd ../
cd /opt/miner

三ヶ月仮想通貨にハマって気づいた事

新年あけましておめでとうございます。うるしです。

ブログ消して作り直しました。 今話題の仮想通貨について記事にします。

はじめに

仮想通貨トレードに数ヶ月触れて得られた成果について話します。ブロックチェーンとかの技術的な話については、他の方のブログについて参照してください。

きっかけ

会社の仲の良い同僚がしばしば投資についての話を振ってくるのがきっかけで、昨年九月以前は株式投資についての話が、初旬に仮想通貨のマイニングをしているという話を聞いたのが始まりでした。

PCの新調とマイニング

会社の同僚が PC の新調をしたいという話を聞き、自分は自作 PC の知識に疎かったので、その知識を仕入れるためにと思い、便乗して大阪の心斎橋まで足を運びました。自分の PC はそこまで古くなかったのですが、Steam で当時も今も流行っている PUBG をやりたかったのでグラフィックボードを新調1し、その元を稼ぐために仮想通貨のMONAコインの採掘を始めました。これが自分と仮想通貨の一番初めの接点です。

加熱する投機

日に日に仮想通貨の価格が上昇していき、同僚は bitflyerZaif といった仮想通貨取引所に資金を投入しトレードを始めたという話をしていました。自分はそれまでに株も含めたトレードの経験が一切なく、正直投機である仮想通貨取引を行うことは特にハードルが高く尻込みしていました。が、同僚の話を聞いている内に、これはやらなければ損だという気持ちばかり生まれてしまい、いざ決心して口座開設。

トレード

トレードは自分のメンタルとの戦いでした。慣れの問題と言われればそうだとしか言いようがないですが、決心して掴んだ BTC とかがちょっとでも値が下ったりすると、気分が下がって落ち込んだり、逆に上がると、テンション高くなってもっと上がれと願ったり、正直色々辛い。投資額としても同僚に比べれば屁でもない金額だし、きっとここで公表したところで笑われるような端金なんですが、それでもメンタルが削られました。

チャート

トレードにはチャート分析が必須です。とりあえず仮想通貨を一年間ホールドしておくか、という訳ではなかった2ので、チャートを見てしっかりどの通貨が上がりそうかを確認して投資していく必要があります。それにはかなりの時間が必要だし、なにより自分にはチャートを見る技術もないので、その勉強から始めないといけない。正直、プログラミングが趣味の自分にはその時間がなくなってしまうのは苦痛でした。そしてなにより、握力が無くて全然稼げなかったのもこれ以上やる気が起こらなかった原因です。(ただ自分が下手くそなのを言い訳にしているだけ)

自動化

ということで、自分には自分なりのやり方があるという事で、トレードの自動化を進めようと思いました。要するにプログラマーなんだから、プログラミングでなんとかしようという発想です。取引所には API が用意されている場合が多く、そこから現在の価格情報や、トレードを行う事が可能です。チャートを見なくて済むように、自分で書いたコードに全てを任せることにしました。(取引やめろなんでいわないで)

実装

高いと思ったら売って、安いと思ったら買う。その判断には各種テクニカル指標だったりを用いて判断する。あとちょっと雑に機械学習をさせてみたりもした。makarel で情報を監視できるようにして、仮想通貨の価格の評価が一定以下、以上になったらアラートを出したりもしました。

まとめ

正直仮想通貨トレードしてたら疲れました。仮想通貨の価格が気になって、他のコード書けなくなるし、ゲームする時間も減るし。人生お金は大事だけどお金だけじゃない。 自動化して雑にトレードして、余った時間は他の事して遊んでます。


  1. 買ったグラボは GTX 1080Ti

  2. 自分は現状仮想通貨のことを信用していないので、ロングで保持することこそ怖いと思っている。特に BTC 。