Android Gradleファイルの階層関係とsettings.gradleについて

Androidの開発をしていると、コードを書いているよりビルドに四苦八苦する時間が多い…ぐらいな気もしてしまいます。

Androidが利用しているビルドツールであるGradleのことについては、大体はAndroid Studioさんがやってくれるので、プログラマの日常業務としてはライブラリの読み込みを編集したり、SDKのバージョンを変更したり、Flavorごとの設定を変更したり…ぐらいなことをやっていて、あんまり理解が進んでいなかったなという気がします。

これにはきっかけがあって、Open Street MapのAndroid組み込み用のサンプルプログラムを自分で使ってみて参考にしようと思ったんですが、Gradle Furyというプラグインを使っていて、結局ビルドできなかったんですよね。Gradle Furyは「Gradleに怒っている人が使う」wwwらしく、POMでいろんなことを定義しちゃおうぜーという試みだったらしいです。

ただ、Gradleのことを全部わかろうというのもちょっと時間の無駄な気がしますね。なので、今回は階層関係と、settings.gradleについて書いておきます。詳しくは、下記の公式サイトで見てみてください。

ビルドの設定

https://developer.android.com/studio/build?hl=JA

Android Studioでプロジェクトを作ると、図のように階層やフォルダができていると思います。(私はWindows 10で開発しています。)


Android StudioでSampleAppというアプリを作ったところ

こんな風に表示されてないよー、という場合は、赤丸してあるところがAndroidになっていると思います。クリックして、「Project Files」にすると、ファイルシステムと同じビューで見れます。この方が、今回はわかりやすいので、この「Project Files」ビューで進めます。

さて、今回最初に話題にしたいのは、下記の水色でマルしたsettings.gradleとbuild.gradleです。

settings.gradleから。中身は下記の一文だけ。


include ':app'

appをつかってビルドしましょうね~って意味でして、これがないと何も始まらないw
今回、一個だけのアプリケーションを使ってビルドするので、一文だけですが、ほかのアプリケーションをモジュールとして利用したい場合、ここにincludeするものが増えていきます。

build.gradleは次の通り。

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
repositories {
google()
jcenter()

}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
google()
jcenter()

}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

ここでは、全部のアプリケーションに共通のビルドの設定を書いておきます。さっきも書きましたが、今回は一つのアプリケーションだけなので、あまり意味がありませんが、2つ、3つと増えてくると、一つ一つのアプリケーションのGradleファイルにbuildscriptとか書くのは「ええい、面倒!」と思ってくると思いますので、意味があります。

次に、図の紫で囲った、一個下のappフォルダ内のファイルbuild.gradleの説明です。中身は

apply plugin: 'com.android.application'

android {
compileSdkVersion 28
defaultConfig {
applicationId "smart.location.admin.sampleapp"
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

で、こっちは見慣れた感じだと思います。こっちで利用するライブラリやビルドタイプなどを決めていきます。

今回は本当に触りだけですが、以上です。

Vagrant + VirtualBox ローカルの開発環境をうっかり消し飛ばした日の話

2019年3月14日 快晴 社員旅行を明日にひかえ、本日も開発日和である。

普段使っている開発環境の挙動が気になり、ゴミファイルの掃除を思いつきました。

私は普段、Vagrant と VirtualBox で作った仮想環境で開発を行っています。

仮想マシンを閉じてもマシンが動いているような気配を感じたスピリチュアルエンジニアの私は、vagrantの様子を伺いました。

こころがおだやかではないので、たんたんとかいてゆきます。
ぜったいにまねしないでください。

>vagrant box list

hogehoge (virtualbox, 0)
piyopiyo (virtualbox, 0)

ここで私はhogehogeの方しか使っていないつもりだったので、piyopiyoを消そうと考えました。

>vagrant box remove piyopiyo
Box 'piyopiyo' (v0) with provider 'virtualbox' appears
to still be in use by at least one Vagrant environment. Removing
the box could corrupt the environment. We recommend destroying
these environments first:

default (ID: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)
default (ID: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)

Are you sure you want to remove this box? [y/N] n

???

なんか2つ動いてる。どういうこっちゃ。

ここでVMの電源をオフにします。

>vagrant box remove piyopiyo
Box 'piyopiyo' (v0) with provider 'virtualbox' appears
to still be in use by at least one Vagrant environment. Removing
the box could corrupt the environment. We recommend destroying
these environments first:

default (ID: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)

Are you sure you want to remove this box? [y/N] n

おっ 片方消えた。残った方何者。

>vagrant global-status
id       name    provider   state    directory
--------------------------------------------------------------------------
aaaaaaa  default virtualbox poweroff C:/test_vagrant/hogehuga
bbbbbbb  default virtualbox running  C:/vagrant_test/hogehuga
ccccccc  default virtualbox poweroff C:/vagrant/test
ddddddd  default virtualbox running  C:/vagrant/hogehuga
eeeeeee  default virtualbox aborted  c:/vagrant/hogehuga

The above shows information about all known Vagrant environments
on this machine. This data is cached and may not be completely
up-to-date. To interact with any of the machines, you can go to
that directory and run Vagrant, or you can use the ID directly
with Vagrant commands from any directory. For example:
"vagrant destroy 1a2b3c4d"

うわなんかめっちゃある。

どうやら過去に使った事があるもの(=キャッシュの残っているもの)は全て表示されているらしい。

>vagrant up

>vagrant global-status
id       name    provider   state    directory
--------------------------------------------------------------------------
aaaaaaa  default virtualbox poweroff C:/test_vagrant/hogehuga
bbbbbbb  default virtualbox running  C:/vagrant_test/hogehuga
ccccccc  default virtualbox poweroff C:/vagrant/test
ddddddd  default virtualbox running  C:/vagrant/hogehuga
eeeeeee  default virtualbox running  c:/vagrant/hogehuga

eeeeeeeのやつのstateが変わった。普段使ってるのはコイツか。

>vagrant global-status  --prune
id       name    provider   state   directory
------------------------------------------------------------------------
ddddddd  default virtualbox running  C:/vagrant/hogehuga
eeeeeee  default virtualbox running  c:/vagrant/hogehuga

ふーん? bbbbbbbお前消えるのか。まあ実体無いしそりゃ消えるか。

>vagrant halt
==> default: Attempting graceful shutdown of VM...

>vagrant global-status
id       name    provider   state    directory
-------------------------------------------------------------------------
ddddddd  default virtualbox running  C:/vagrant/hogehuga
eeeeeee  default virtualbox poweroff c:/vagrant/hogehuga

eeeeeeeが停止するよなぁそうだよなぁ。
それはいいんだけど走り続けるddddddd何者なんだ。

>vagrant box list
hogehoge (virtualbox, 0)
piyopiyo (virtualbox, 0)
>vagrant box remove hogehoge
Box 'hogehoge' (v0) with provider 'virtualbox' appears
to still be in use by at least one Vagrant environment. Removing
the box could corrupt the environment. We recommend destroying
these environments first:

default (ID: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)

Are you sure you want to remove this box? [y/N] n

適当にコマンドを打ち冷静になろうとした。

>vagrant destroy ddddddd
    default: Are you sure you want to destroy the 'default' VM? [y/N] n
==> default: The VM 'default' will not be destroyed, since the confirmation
==> default: was declined.
>vagrant package
==> default: Clearing any previously set forwarded ports...
==> default: Exporting VM...
==> default: Compressing package to: C:/vagrant/hogehuga/package.box

おもむろにバックアップを残そうとする。

>vagrant destroy ddddddd
    default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Destroying VM and associated drives...

あ、今回あっさり消えた。なんで。仮想マシン切ったっけな?

>vagrant global-status
id       name    provider   state   directory
------------------------------------------------------------------------
ddddddd  default virtualbox running C:/vagrant/hogehuga

>vagrant global-status  --prune
id       name   provider state  directory
--------------------------------------------------------------------
There are no active Vagrant environments on this computer! Or,
you haven't destroyed and recreated Vagrant environments that were
started with an older version of Vagrant.

消えてる。

>vagrant box list
hogehoge (virtualbox, 0)
piyopiyo (virtualbox, 0)

piyopiyo消えないかな?

>vagrant up

>vagrant box list
hogehoge (virtualbox, 0)
piyopiyo (virtualbox, 0)

>vagrant global-status
id       name    provider   state   directory
------------------------------------------------------------------------
fffffff  default virtualbox running C:/vagrant/hogehuga

>vagrant halt
==> default: Attempting graceful shutdown of VM...

>vagrant global-status
id       name    provider   state   directory
------------------------------------------------------------------------
fffffff  default virtualbox unknown C:/vagrant/hogehuga

???

――あれ、なんかローカル環境でDBにログインできなくなった。

すっかりvagrantとの戯れを楽しんでしまい、異変に気付くのが遅れました。

サービスもなんかダメだぞなんだこれ?? なんか下手なもん消したか??

やらかした感が溢れだします。面倒なことになりました。

>vagrant up

>vagrant ssh
Last login: Fri Mar 16 14:34:16 2018 from 10.0.2.2
Last login: Fri Mar 16 14:34:16 2018 from 10.0.2.2
Welcome to your Vagrant-built virtual machine.

>vagrant box list
hogehoge (virtualbox, 0)
piyopiyo (virtualbox, 0)

>vagrant box remove piyopiyo
Removing box 'hogehoge' (v0) with provider 'virtualbox'...

>vagrant box list
hogehoge (virtualbox, 0)

>vagrant global-status
id       name    provider   state   directory
------------------------------------------------------------------------
fffffff  default virtualbox unknown C:/vagrant/hogehuga

……(新しくboxから開発環境を復旧させようとする音)

[root@localhost ~]# mysql
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
[root@localhost ~]# mysql -u root
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
[root@localhost ~]# mysql -u root -p
Enter password:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

……(裏でmysqlにアクセスができないことを確認している図)

自分の設定したパスでローカルにアクセスできないってのは恐らく、DBが太古の昔(自分がこのDBデータを先人から受け取ったあの日)に戻ってしまったからですね。

……(mysqlのパスを再設定する音

お、DB入れた。

あ、DBのデータが以前のものに戻ってる……

Vagrantをup/haltしても全く動かず電源オフのままであるような、よくわからない仮想マシンを1機削除していたことを思い出し、本件の原因は九割九分九厘それであることを理解しました。

やれやれ。

boxファイルにDBをバックアップしたい。(できるのかな?)

教訓

  • よくわからないデータやファイルを適当に削除するのはやめましょう。
  • 削除前にはバックアップを取るなど、備えを怠らないようにしましょう。

参考

不用意なリソース削除には気をつけよう!

Ghost Inspector の実行APIを試してみる

Ghost Inspector にテストsuiteを実行するためのWebhookがあることに気付いたので、試してみることにしました。

実行API (Webhook URL)

公式のAPIドキュメント によれば、Ghost Inspectorのテストsuite実行APIは、以下の形式になっています。

https://api.ghostinspector.com/v1/suites/<suiteId>/execute/?apiKey=<apiKey>&startUrl=<startUrl>
suiteIdテストsuite画面のアドレスの末尾にある英数字部分です。
https://app.ghostinspector.com/suites/xxx... ←これのxxx...の部分)
apiKey Account Settings > API Access にあるAPI Keyをコピペします。
横にある[Regenerate API Key]は鍵の再生成ボタンなので注意します。
startUrlテストのStart URLが指定できます。(省略するとテストの設定が参照されるっぽい?)
テストの設定が参照される方が嬉しいので、今回は省略します。

というわけで、今回試すWebhook URLは以下のような形になります。

https://api.ghostinspector.com/v1/suites/xxxxxxxxxxxxxxxxxxxxxxxx/execute/?apiKey=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

さあ叩こう

とりあえず、Webhookを叩いてみます。今回はPythonでやってみることにしましょう。

今回、HTTPリクエストの送出には requestsを利用するので、pip等でインストールします。

pip install requests

下記のサイトを参考に、Webhook URLを叩くコードをさっくりと書いていきます。

PythonでSlackのIncoming Webhookを試してみる

先程のWebhook URLをそのまま踏んづけてもテストは実行されるけど、せっかくなのでそれっぽく書いて動作確認。

こちらを実行してみると……Ghost Inspectorのテストが走ります!やったぜ。

もちろんテストの通知設定に従って通知も飛びます。

GETで簡素にやる場合は以下みたいな感じ。

ちなみにrequestsのレスポンスはテストが走り終わるまで返ってこないので、ここでは特に見ていません。
レスポンスに異常があれば、別途Slackに投稿されるような仕組みにしておくと、テストの実行失敗時も検知できて安心感が高まる。

所感

実務的には、動作確認用環境(いわゆるテストサイト/テスト環境)にサービスをデプロイしたあとに、Webhookが自動で叩かれてテストが走る……という流れになると良さそうですね。
テストのし忘れがなくなっていい感じ。

参考

NumPy.add.atなどのユニバーサル関数+at

NumPyについて書くシリーズの続きです。

ユニバーサル関数(ufunc)とは、ベクトル化演算です。いくつもの要素がある中で、一つ一つ処理するよりも、一度に処理したほうが早いですよね。そういうことをやってくれる関数です。

たい焼きを焼くときに、一つ一つ焼いていると大変です。しかし、たい焼き屋さんでは、いくつものたい焼きの穴が開いている鉄板で一度にたくさんのたい焼きをバシッ!!と作りますよね。あんこを足すときも、一度にできて早いですよね。あれのイメージです。

で、今回は、特にそのユニバーサル関数を at と組み合わせた時の動作がちょっとわかりづらかったので書いておきます。

下記の公式サイトにある
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.at.html
例なのですが

import numpy as np

a = np.array([1, 2, 3, 4])
np.add.at(a, [0, 1], 1)
print(a)
#下記が出力されます。
array([2, 3, 3, 4])

これを例にとって説明するとadd.atの

・1番目の引数は処理する配列

・2番目の引数は処理したいインデックス

・3番目の引数は、addしたい数

です。

私はPHPとかJavaとかが長いので、こういう「1を加算する」的な処理はついついfor文とかでループで書いてしまいがちなのですが、速さが違うので、NumPyのユニバーサル関数を使いこなしていきたいと思います!!

Outlook メール送信時にSlackに投稿する

WordやExcel等の例に漏れず、Outlookもマクロが組めます。

メール送信時のアクションとして、SlackのIncoming Webhookを叩いてみます。

タスク管理などに応用できるかも?

Outlookでマクロを使うための下準備

マクロを組む準備と、マクロを実行できるように設定をいじります。 Outlookのメニューバーから操作します。

  1. ファイル > オプション > ユーザーリボン と選択し、開発 をONにする
  2. メニューバーに、開発タブが表示される
  3. 開発 > Visual Basic を開いて作成する

Webhookを利用してSlackに投稿する

この記事の例では、SlackのIncoming Webhookというインテグレーションを利用します。

Incoming Webhookの利用については、以下の記事に説明があります。

Slack Incoming Webhookの利用

マクロの作成

Incoming Webhookが発行する受信用URLにHTTPリクエストを送信し、Slackへの投稿を行うサンプルです。

開発 > Visual Basic > 画面左上のProject1以下を展開 > ThisOutlookSessionを開きます。

ThisOutlookSessionに以下を記述して保存します。

Outlookから送信したメールを、SlackにもPOSTします。

TargetURL = "https://hooks.slack.com/services/…"

12行目のTargetURLには、Incoming Webhookで生成したURLを指定します。

sendText = "payload={""text"":""件名: " & objMail.Subject & "\n本文: " & Left(objMail.Body, 200) & """}"

17行目のsendText部分が、実際にWebhookのURLに送信される内容です。メールの件名と本文をPOSTしています。

Left(objMail.Body, 200)

メールの引用などで本文が長すぎると投稿が大変なことになるため、sendText内の上記部分で、半角200文字分だけ投稿されるようにしています。

こんな具合に投稿されます

指定チャンネルへのPOST

デフォルトでは、マクロからPOSTした内容は、Incoming Webhookで設定してある送信先チャンネルに投稿されるようになっています。

sendTextの部分でchannelプロパティを指定することで、任意のpublicチャンネル、ユーザーのDMへ投稿することが可能です。

  • randomチャンネルへの投稿
sendText = "payload={""channel"":""#random"", ""text"":""件名: " & objMail.Subject & "\n本文: " & Left(objMail.Body, 200) & """}"
  • 特定ユーザーのDMへ投稿
sendText = "payload={""channel"":""XXXXXXXXX"", ""text"":""件名: " & objMail.Subject & "\n本文: " & Left(objMail.Body, 200) & """}"

XXXXXXXXXの箇所は、Slackのchannel/ユーザーの識別IDです。チャンネル名あるいはユーザー名を右クリックして取得します。

※右クリック > リンクをコピー > 以下のような形で取得できるリンクの、末尾部分がIDになります。

https://hogehoge.slack.com/team/XXXXXXXXX

投稿にメンションを含める

SlackのIncoming Webhooksでメンションを飛ばす方法を参考にする。

sendText内、textプロパティにて、以下の書式に則ってメンションを記述することができます。

記法メンション
<!here>@here
<!channel>@channel
<@user_id>@michael

記述例

sendText = "payload={""text"":""<!channel> 件名: " & objMail.Subject & "\n本文: " & Left(objMail.Body, 200) & """}"

マクロ作成後、実行できない(有効にならない)場合

マクロの実行時に警告が出て実行できないなどがあれば、署名の作成を行うと解決する場合があります。マクロのセキュリティ設定で、署名のないマクロをブロックするようになっていることが多いです。

最近では下記のファイルを直接実行してデジタル署名を作成するらしいですが、ちょっと怖いですよね。

※ 署名を作らなくてもマクロを有効にできます。何か起きても責任は取れません。

C:\Program Files\Microsoft Office\root\Office16\SELFCERT.EXE

署名の作成を行ったのにまだマクロが動いてくれない場合、一度警告を出させ、明示的に実行を許可してやるとうまくいくケースがあります。
署名を作成しない場合でも、この手順は有効みたいです(動いた例あり)。

  1. (Outlookのメニューバー)開発 > マクロのセキュリティ を開く
  2. すべてのマクロに対して警告を表示する にチェックして保存
  3. Outlookを再起動
  4. マクロの実行について警告のポップアップが表示される
  5. 実行を許可し、マクロを有効化
  6. マクロの動作をテストし、動いたらガッツポーズ

※ 署名を付けてマクロを作成した場合は、ここで署名単位で実行を許可することができます。後々マクロの変更とか作成とかした際に実行許可の手間が省けるとかそういう話です。

参考