読者です 読者をやめる 読者になる 読者になる

CORDEA blog

Programming及びFedora21等のLinux OSのことが多めです。

Jenkins の Android アプリ "Butler" を作った

Android Kotlin

Jenkins のクライアントアプリを作成しましたのでご報告。
もちろんオープンソースですが、今回ストアには公開していません。


github.com



ストアに公開しなかった理由についてですが、
アプリ的にではなく、API 的に公開できる品質にならなそうだと判断しました。
具体的には、ユーザー一覧など、多すぎるとタイムアウトしてしまう点です。
調べた限りではページング等できなさそうだったので、ここの改善は難しいと考えています。
そこらへんできる方法あれば教えていただけますと幸いです。

特徴

screen shot は GitHub をみてください。

アプリ的特徴

  • ビルド、プロジェクト、コンピューター、ユーザーの確認
  • ビルドの実行 (一部対応)

特徴

  • Kotlin
  • Data binding

まとめ

今買うの私的な挑戦は、Kotlin + Data binding の組み合わせを用いることで、
RxKotlin を使用しなかったことです。

Rx は流行りもあって広まっていますし、使用する人も増えていますが、
設計如何では、恐ろしいコードが生成される傾向があります。

そういうのをいくつかみてきたので、最近では Rx を使わない道を模索しており、今回のアプリはその一環です。
とはいえ、今回は MVVM を意識した作り (Data binding を使用しているので当たり前といえば当たり前ですが) なので
Rx を使ってもそれほど酷くはならなかったかもしれません。

あと、Kotlin は Observable とかあるので、使わなくても十分対応できるよねってところがあります。

Mackerel Client もまるごと書き直したい...


ストア公開する予定がないため、使いたい方はビルドして使ってみてください。apk もどこかに置く予定はあります。

Windows で perl5 の DBI モジュール使って嵌った話

perl Database

perl5 の DBI モジュールを使用する際で
data_source の指定パスに日本語含まれてる場合に嵌った。


環境

>perl --version

This is perl 5, version 22, subversion 1 (v5.22.1) built for MSWin32-x64-multi-t
hread
(with 1 registered patch, see perl -V for more detail)

Copyright 1987-2015, Larry Wall

Binary build 2201 [299574] provided by ActiveState http://www.ActiveState.com
Built Jan  4 2016 12:12:58

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

結論

connect する際に utf8 にエンコードするといける
アプローチがあってるかどうかは謎

良いアプローチあったら教えてください


 

テスト

#!/usr/bin/perl
use strict;
use warnings;
use utf8;

use Encode qw/encode decode/;
use DBI;

my $file_enc = "cp932";

binmode(STDIN,":encoding($file_enc)");
binmode(STDOUT,":encoding($file_enc)");
binmode(STDERR,":encoding($file_enc)");

my $db_loc = $ARGV[0];

my $data_source = "dbi:SQLite:$db_loc";
my $dbh = DBI->connect($data_source);

$dbh->disconnect;
print "できた";
結果
>perl test.pl ほんとやめて\test.db
DBI connect('\x{0082}U\x{0082}n\x{0082}A\x{0082}a\x{0082}s\x{0082}A\test.db','',
...) failed: unable to open database file at test.pl line 21.
Can't call method "disconnect" on an undefined value at test.pl line 23.

修正

#!/usr/bin/perl
use strict;
use warnings;
use utf8;

use Encode qw/encode decode/;
use DBI;

my $file_enc = "cp932";

binmode(STDIN,":encoding($file_enc)");
binmode(STDOUT,":encoding($file_enc)");
binmode(STDERR,":encoding($file_enc)");

my $db_loc = $ARGV[0];

my $utf8_db_loc = decode($file_enc, $db_loc);
$utf8_db_loc = encode("utf8", $utf8_db_loc);

my $data_source = "dbi:SQLite:$utf8_db_loc";
my $dbh = DBI->connect($data_source);

$dbh->disconnect;
print "できた";
結果
>perl test.pl ほんとやめて\test.db
できた


python2 でこの類は慣れてるつもりだったけど
perl5 は格が違った
もう Windows + 日本語は本当につらい

Kotlin + OkHttp3 + Retrofit2 でヘッダの追加とか

Android Kotlin

Kotlin でアプリ書いてる時にちょっと戸惑った


 

OkHttpClient のヘッダーの追加は

val httpClient =
                    OkHttpClient.Builder()
                            .addInterceptor {
                                it.proceed(it.request()
                                        .newBuilder()
                                        .addHeader("Content-Type", "application/json")
                                        .build())
                            }
                            .build()


これを Retrofit で使用する場合

Retrofit.Builder()
                .baseUrl { HttpUrl.parse(url) }
                .client(httpClient)
                .build()
                .create(HogeHogeApiInterface::class.java, context)
                .postHuge()
                ...


Observable 返したい場合や、gson 使いたい場合
ここらへんは java と変わり無いですが

Retrofit.Builder()
                .baseUrl { HttpUrl.parse(url) }
                .client(httpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                ...

ちなみに HttpLoggingInterceptor 使う場合

val httpClient =
                    OkHttpClient.Builder()
                            .addInterceptor {
                                ...
                            }
                            .addInterceptor(okhttp3.logging.HttpLoggingInterceptor()
                            .setLevel(okhttp3.logging.HttpLoggingInterceptor.Level.BASIC))
                            .build()


実際に使ってるのはここらへんです。

もうちょっと知見が集まってくれると Kotlin 使う人は増えそうな気がする

Blackberry 10 での Json の扱い方について

Blackberry

Blackberry OS 10 のネイティブアプリ開発で Json を扱うことがあったのでメモ

C++Json を扱う場合、Cascades framework にある JsonDataAccess を用いるのが簡便だと思います。
Qt の対応バージョンが 4.8 で、Qt5.5? で追加された Json サポートを利用することができないためです。
使おうと思えば Qt5 も使えるようなので、その場合は Qt の Json サポートを利用するのがよいかもしれません。

qml で使用する場合は、JSON.parse() で行けるはず。

Parse

    QString jsonData = ....

    JsonDataAccess jda;
    QVariant var = jda.loadFromBuffer(jsonData);

    // map
    QVariantMap map = var.value<QVariantMap>();
    // list
    QVariantList list = var.value<QVariantList>();


レスポンスとして Json が返ってくる場合、このような使い方になります

QVariantMap ApiRequest::onRequestFinished(QNetworkReply* reply)
{
    if (reply && reply->error() == QNetworkReply::NoError) {
        const QByteArray buffer(reply->readAll());

        JsonDataAccess jda;
        QString jsonData = "hogehoge";
        QVariant var = jda.loadFromBuffer(jsonData);
        QVariantMap map =  var.value<QVariantMap>();
        ...
    }
}

 

Stringify

    QVariantMap map;
    map["hoge"] = "hogehoge";

    JsonDataAccess jda;

    QByteArray jsonString;
    jda.saveToBuffer(QVariant(map), &jsonString);


POST リクエストとか送る時はこんな感じ

void ApiRequest::request(QString username, QString password, QString factorKey)
{
    QNetworkRequest request;
    request.setUrl(QUrl("http://cordea.jp"));

    connect(mManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onRequestFinished(QNetworkReply*)));

    QVariantMap map;
    map["hoge"] = "hogehoge";

    JsonDataAccess jda;
    QByteArray body;
    jda.saveToBuffer(QVariant(map), &body);

    mManager->post(request, body);
}


c++ 的に書き方があっているかは若干不安。


F# で Android アプリ開発いいよねって話を今更。

Xamarin Android

Xamarin と F# 使って Android アプリ開発の話。

最近 F# とか blackberry とかやってて完全に変人扱いされています。
ですが、Rx とか流行ってるし、次にくるのは F# だと信じています。


Android Java or Kotlin はもちろん、
Xamarin C# に比べても人口も情報も圧倒的に少ないですが
でも IDE があって、サポートされているだけでも上々ですよね。

F# のよさを語るよりも実際にコードを見ていただいたほうが魅力が伝わるかと思いますので、
おなじような実装を Java, C#, F# でしてみました。

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    ListView listView = (ListView) findViewById(R.id.list_view);
    listView.setAdapter(adapter);

    Context context = this;
    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(context, TestActivity.class);
            startActivity(intent);
        }
    });
}

C#

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);
    SetContentView (Resource.Layout.FirstView);

    var toolbar = FindViewById<Toolbar> (Resource.Id.toolbar);
    SetSupportActionBar (toolbar);

    var listView = FindViewById<ListView> (Resource.Id.list_view);
    listView.Adapter = adapter;

    FloatingActionButton fab = FindViewById<FloatingActionButton> (Resource.Id.fab);
    fab.Click += (sender, e) => {
        StartActivity (typeof(TestActivity));
    };
}

F#

override me.OnCreate (bundle) =
    base.OnCreate bundle
    me.SetContentView Resource_Layout.Main
    
    let toolbar = me.FindViewById<Toolbar> Resource_Id.toolbar
    me.SetSupportActionBar toolbar
   
    let listView = me.FindViewById<ListView> Resource_Id.list_view
    listView.Adapter <- me.adapter
    
    let onClick e =
        let intent = new Intent(me, typeof<TestActivity>)
        me.StartActivity intent
        
    let fab = me.FindViewById<FloatingActionButton> Resource_Id.fab
    
    fab.Click.Add(onClick)


どうでしょうか。
個人的には brace ないだけでもかなり見通し良いと思っています。

Xamarin を使用されている方もいない方も、ぜひ一度 F# を。



F# でもうちょっとちゃんと実装してあるものはこちらのリポジトリにあります。
github.com
blackberryiOS なども突っ込まれててカラフル。

その Activity 、少し長すぎませんか?

Android

Android の Activity や、layout xml, 気をつけていても長くなってしまう場合があります。

そして、特に一人で開発していたりすると、
長すぎることに気づいてもついつい放置してしまいがちです。

ただ、放置すると、多くの場合引継ぎ等に支障をきたします。
layout xml とかあまりに長すぎると補完聞かなくなったりしますしね...

というわけで、
今回は java file や layout xml が指定行数を超えるとビルドが通らなくなる方法を検討してみました。


checkFileLimits() をビルドの際に呼び出すことで
指定行数を超えるとビルドが通らなくなります。

import groovy.io.FileType

class LineLimit {
    void checkFileLimits(base, layoutLimit, javaLimit) {
        def layout = base + "/src/main/res/layout/"
        def java = base + "/src/main/java/"
        checkLimit(layout, layoutLimit)
        checkLimit(java, javaLimit)
    }

    void checkLimit(dir, limit) {
        new File(dir).eachFileRecurse(FileType.FILES) {
            def c = it.text.split("\n").size()
            if (c >= limit) {
                throw new Exception("File exceeds the limit. Number of lines: " + c + ", File name: " + it.name)
            }
        }
    }
}


 

    buildTypes {
        debug {
            def lineLimit = new File(projectDir.absolutePath + "/LineLimit.groovy")
            def sc = new GroovyClassLoader().parseClass(lineLimit)
            def llClass = sc.newInstance()
            llClass.checkFileLimits(projectDir.absolutePath, 499, 999)
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }


 

method の呼び出しが美しくないので
ここらへんは groovy, gradle に明るい方に教えていただきたい

Mackerel の非公式 Android アプリ "Mackerel Client" を公開しました

Kotlin Android

サーバ管理サービス、Mackerel(マカレル)の Android アプリを作ったので、ストアに公開しました。
と同時に、GitHub にソースを公開しました。

Get it on Google Play

github.com


Kotlin を使って何か作りたいと思っていた時期に
Mackerel の API が提供されていることに気づいたので
とても良いタイミングでした。

 

アプリの特徴

  • アラート・監視設定・ホスト等の情報閲覧
  • アラートのクローズ、監視設定の削除、ホストの退役
  • メトリックグラフの表示


情報の確認を出先でする、という目的のもとに作っていますので
情報の編集等は現時点では実装していません。
ホストの退役も出先ではやらないだろうな...

技術的な特徴

  • Kotlin (重要)
  • Rx


今回は、いろいろと新しいものを取り入れて
ひたすら自由に作っているので、嵌りどころもありました。
そこらへんは後日記事にします


あと、Kotlin + RxKotlin は良いなぁと改めて思いました。
業務で Kotlin 使えるのはいつになるか分かりませんが、個人的には今後も使っていく予定です。


開発では Mackerel のヘルプが充実していて助かりました。
API 仕様が読みやすくてとても良かったです。