Javaで試行錯誤の際のTips : Java Api Examples #ことクロ9


"Kotlinでスマートフォン・クロスプラットフォーム開発の試行錯誤(人柱)の記録メモ"、
略して、"ことクロ"シリーズ その9。

1) "このAPI、どう呼べばいいのか?"などなどの試行錯誤

マイナーな実装案件、例えば、Android/iOS両対応のクロスプラットフォーム開発をRoboVMで行う(さらには言語はKotlin)、では、インターネットの情報が頼り。欲しい情報は、一般論ではなく、具体的な実装例。

とりあえず、ぐぐりながら前に進むうちに、programcreekなるサイトの以下にたどり着く:

=> リンク先

#2008年からある、けっこう古株なので、知ってる人は知ってるのだろう。自分は{知らな|覚えていな}かった。
ちなみにPython版などもある(内容は未検証):
=> リンク先

要するに、Java APIとして公開されているものの実装例をキーワード検索してインデックスしているサイトらしい。実装例の数別にランキングされていて、上位10000件が以下から辿れる

自分が欲しかったrobovmのAPI実装例は、3520番台にランキングされていた(カッコ内が実装例の件数):

3521. com.vividsolutions.jts.geom.Coordinate    (143) 
3522. java.io.FilterWriter  (143) 
3523. org.apache.http.NoHttpResponseException   (143) 
3524. com.badlogic.gdx.backends.iosrobovm.IOSApplication    (143) 
3525. org.springframework.beans.factory.support.BeanDefinitionRegistry  (143) 
3526. com.badlogic.gdx.backends.iosrobovm.IOSApplicationConfiguration   (143) 
3527. org.eclipse.debug.core.ILaunchConfigurationType   (143) 
3528. javax.lang.model.type.TypeKind    (143) 
3529. net.minecraft.entity.projectile.EntityArrow   (143) 
3530. android.text.style.UnderlineSpan  (143) 

いろいろありそうなのが分かるだろう。

Javaでまさしく今、試行錯誤中の人は適宜参考して欲しい。
以下は、、Android開発に自信がある人がクロスプラットフォーム開発環境RoboVMでiOS開発に乗り込むためのおまけ記録:

2) (メモ書き)Java Api Examplesにたどり着くまで

2-1 先人が倒れてもRoboVMで人柱するぞ (ぐへへ)

RoboVMのような新参者にも、人柱した先人はいるもの。その時々の人柱の結果は、必ずしも肯定的なものではない(...というか、疲れたとか大変とかいう情報が多い)

例えば、そのまんまのタイトルの : 結局RoboVMは使うのを辞めました。

それでもRoboVMを使おう、という自分の頭の中を要約:

  • RoboVMは、Android開発者に馴染みの深いAndroidStudioベース。
  • 現状のRoboVMはiOS向けのUIデザインをXCodeに委ねる方針(@IBOutlet等のアノテーション経由)。
  • 少なくとも入門段階では、UIデザインをコードで書いた方が良いと思う(すなわち、RoboVMのみを使用して、iOS開発を学んでいく。)
  • ほんとに生産性を高めるためには、クロスプラットフォーム開発向けのデザイン支援ツールが欲しいところ(イメージはHTMLに対するslimとかjadeとかのようなもの)
  • といっても、クロスプラットフォーム開発向けのデザイン支援ツール、DIとかの兼ね合いを考えると意外に難しいのでは。
  • いやいや、KotlinでDSL作ってしまえば、あんなことやこんなことも... グヘヘ...

(あまり盛り上がりすぎると後で失望がおおきいので、ここで止めて、コードの方に戻る)

# 以下はKotlinのコードだけれど、Javaでも共通する内容。Javaで以下と同趣旨のコードは、RoboVMまとめなどにある。RoboVMまとめは、数カ月前までのRoboVMの状況かいろいろ記されているので、RoboVMで人柱したいJavaの人もKotlinの人も適宜参考にしよう。

2-2 RoboVMが自動生成するコードを眺める。

自動生成されるコードはぱっと見、難しくはない。

MyViewController.kt
package com.mycompany.myapp

import org.robovm.apple.uikit.UILabel
import org.robovm.apple.uikit.UIViewController
import org.robovm.objc.annotation.CustomClass
import org.robovm.objc.annotation.IBAction
import org.robovm.objc.annotation.IBOutlet

@CustomClass("MyViewController")
class MyViewController : UIViewController() {

    private val counterStore = CounterStore()

    @IBOutlet
    private val label: UILabel? = null

    @IBAction
    private fun clicked() {
        counterStore.add(1)
        label!!.text = "Click Nr. " + counterStore.get()
    }
}

@CustomClass等のアノテーションが、名前空間org.robovm.objc.annotationと紐付いていることが分かる。名前の通りこれは、Objective-Cオブジェクトに属しており、plist(XMLファイル)経由で、XCodeによって制御される。もちろん、こちらを出発点にして行っても良いのだけれど、iOS開発未熟者としては、全体像が見通せない予感がする。ということで、すべてをコード(私はKotlin)で書いていく。

なお、CounterStoreというのは、以下のフォルダ構成にあるように、Android側との共通モジュールにあたるCore配下にある。

[参考] フォルダ構成 :

2-3 UI要素をコードで追加開始(同類roboscalaを参考に。)

残念ながら、github等には、現バージョンのRoboVMで動くKotlinのコードは無いようなので、roboscalaのコードを参考にさせてもらった。こちら、Pure ScalaでRoboVM開発を進めようと頑張っているプロジェクト(gradleではなくsbtベース)。
https://github.com/roboscala

MyViewController改1.kt
package com.myapp

import org.robovm.apple.uikit.* // UILabel,UIViewController etc.
import org.robovm.apple.foundation.* // NSSet etc.
import org.robovm.objc.annotation.* // CustomClass,IBAction,IBOutlet
import org.robovm.apple.coregraphics.CGRect


@CustomClass("MyViewController")
class MyViewController : UIViewController() {
    private val counterStore = CounterStore()

    // Code Only.
    val textField = UITextField(CGRect(20.0, 190.0, 280.0, 48.0))
    override fun viewDidLoad() {
        textField.setContentVerticalAlignment(
                  UIControlContentVerticalAlignment.Center)
        textField.setBorderStyle(UITextBorderStyle.RoundedRect)
        textField.setClearsOnBeginEditing(true)
        textField.text = "ここに文字列を入力"
        getView().addSubview(textField)
    }

    // XCode Storyboard based code
    @IBOutlet
    private val label: UILabel? = null

    @IBAction
    private fun clicked() {
        counterStore.add(1)
        var name = textField?.getText() ?: "未設定"
        label!!.text =  "${counterStore.get()}回目:${name} です。"
    }
}

"Code Only"以下のところで、TextField要素を追加している。元のScalaのコードとの違いは、CGRectの引数が整数値(20)であるか実数値(20.0)であるか、くらい。

エミュレータでの実行例:

2-4 さて、すべてをKotlinコードにする。DIもしよう...ぐぬぬ。

ボタンクリック時のイベント処理のpure scalaコードはなかった。ということでjavaの実装例をググって
見て、変換をかけ(RoboVM含むIntelliJ系のツールでは、Java->Kotlinの自動変換が可能)、動くコードにしていく。

        btn1.addOnTouchUpInsideListener(object:OnTouchUpInsideListener {
            override fun onTouchUpInside(c:UIControl, e:UIEvent) { onClicked() }
        })

...objectとかなるほどだけど、なんかかっこ悪いなぁ。...ぐぬぬ。

さて、DIは、先人に学んでこんな感じで

    //DIによる初期化
    private val context = getApplicationContext()

    instantiateInjector(con)

    fun instantiateInjector(context :android.content.Context) {
        val appModule = AppModuleImpl(context)
        val dataModule = DataModuleImpl(appModule)
        ...
        Inject.instance = InjectorImpl(appModule, domainModule...)
    }

なんとかなった。だけれど、こちらは、Android環境向けのDI実装。iOSにも対応できるDI実装にするにはどうしたら...ぐぬぬ。

2-5 ...ぐぬぬの壁、Java Api Examplesと共に乗り越えられるか。

人柱実装、あれもこれもこうしてああして、... グヘヘ...と始めた話が、...ぐぬぬ。となるのはよくある話。

そんな時に、robovm.apple.uikit.UIButton(uikitのroboVM社によるJavaラップ)でぐぐったら、Java Api Examplesにたどり着きました。

Java Code Examples for org.robovm.apple.uikit.UIButton

ああ、こんなマイナーな話の実装例が10も出でくるなんて、素敵。

......単にググる時間節約出来るだけなんだけど、Java&JVM言語で試行錯誤のお供にはなってくれるね。