AndroidStudioでAndroid開発環境構築の一連の流れをさらってみた

#AndroidStudioを用いた開発環境構築の一連の流れ

Androidアプリを開発するためにやったこと準備一式を纏めてみる。
AndroidStudioを使ってモバイルアプリ開発環境を作成するのが大目標。

##注意点
実はQiita記事にしたのは更新日の通りなのだが、
この資料を書いたのは1年ぐらいは前なのである。
ので、この記事は2019年12月ぐらいの記事だと思ってみてほしい。

去年のカレンダーに載せたい。


##成果物やScopeについて
Androidアプリの開発環境の作成を目指し、以下を行う。

- AndroidStudioのインストールやセッティング
- エミュレータのセッティング
- Projectの作成やbuild_gradleの設定
- 静的リソースの配置
- ライブラリの読み込み方法
- テストで有用なライブラリの紹介

実際のアプリ作成ノウハウについてはスコープ外

では、れっつごー

##AndroidStudioのインストール
公式のインストールガイドはこれ
https://developer.android.com/studio/install?hl=ja

この指示通りでいい（エミュレータ機能や高速化の設定とかも入れてくれる）が、ひとつだけ。
インストール完了して初回起動時に、
`Unable to access Android SDK add-on list`
というメッセージか来ることがある。
ネットワークでSDKが落とせてこないために言われている。
大抵の場合proxyが通れてないので、この設定を入れれば解決する。

メッセージのガイドに従うか、
一度AndroidStudioの起動完了まで行きConfigure>Setting>Appearance & Behavior>System Settings>HTTP Proxyを選択して、
proxyの設定を入れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445910/3a57d414-9e2c-565f-4eca-f0d08ab2b682.png)

Host nameにはhttpの記述はいらない（ホスト名のみでok）。
入力したらcheck connectionのボタンを押して、接続テストに用いるURLを選ぶ（https://www.google.com/とかでいい）
successfullしたらプロキシ設定完了

##プロジェクトの作成
`Start a new Android Studio project`からprojectを作成できる

- 起動時の画面レイアウト
    - どれでもいい
- projectの名前
- packageの名前
- ディレクトリ位置
- 言語（Java or Kotlin）
    - Javaを選択
- minimum APIレベル
    - どのAndroidバージョンまで対応するかの値（詳細はbuild.gradleの部分で後述）。新しいやつにすると、Androidのバージョンが古い人は利用できなくなる
    - 利用者割合の概算が表示される！ので、参考にするといい
- instant appsの初期設定の要不要
    - アプリをインストールしなくてもリンクを踏むだけでネイティブアプリを利用できるようにする機能。その代わりアプリの機能ごとにモジュール分割するなど諸作業が必要
    - 詳細はscope外なので割愛。私のような初心者はチェックは外しておく。


###プロジェクト作成時にでやすそうなエラーや警告について

```
Android Studio is configured to use a HTTP proxy. Gradle may need these HTTP proxy settings to access the Internet (e.g. for downloading dependencies.)  Would you like to copy the IDE's proxy configuration to the global gradle.properties file?  Note: To avoid potential security vulnerabilities, passwords will not be copied to the gradle.properties file. You can manually copy passwords to the gradle.properties file at your own risk.  For more details, please refer to the Android Studio documentation.
```

Gradleが使用するproxyの設定をAndroidStudioの設定から自動生成するかどうか。
基本yesでいいが、パスワードは書かれない（直書きを防ぐため）ので、そこは自分で設定が必要

```
ERROR: Failed to install the following Android SDK packages as some licences have not been accepted.
   build-tools;28.0.3 Android SDK Build-Tools 28.0.3
   platforms;android-28 Android SDK Platform 28
To build this project, accept the SDK license agreements and install the missing components using the Android Studio SDK Manager.
Alternatively, to transfer the license agreements from one workstation to another, see http://d.android.com/r/studio-ui/export-licenses.html
```

対象とするSDKがローカルにない（ライセンス利用の同意もしていない）。SDK manager(Tool>SDK Manager)から落としてこれる

```
Android Studio is using this JDK location:
/path/hoge/jre
which is different to what Gradle uses by default:
/path/huga/jre
Using different locations may spawn multiple Gradle daemons if
Gradle tasks are run from command line while using Android Studio.
```

AndroidStudioで使うJDKとコンソールで使うJDK(JAVA_HOME)が同一でない警告
ツールバーのFile>Project StructureからSDK Location>JDK LocationをJAVA_HOME（プルダウンメニュー内にある）を選択すると
AndroidStudioもJAVA_HOMEのJDKを使うようになる


##エミュレータの作成
ツールバーのTools>AVD Managerでエミュレータの作成ができる

左下、Create Visual Deviceから、対象の機器とsystem imageを選択してエミュレータを作成する。
Play Storeがあるやつを選んだ方がいいらしい？（高速化の対象になるため）



##作成されたプロジェクトの構成を説明
プロジェクトの構成は以下の様になっている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445910/05972998-583e-d894-f716-64890b0fcbd1.png)


ProjectタブのバーのAndroidをProjectに変えれば実際のディレクトリ構成を表示できる（画像左上）
特に重要なのは、2つの`build.gradle`とmanifestに存在する`AndroidManifest.xml`

### build.gradle（project root直下）
project全体のビルドの設定を記載する。アプリケーション（モジュール）由来の設定は入れない。
AndroidStudioの初期では依存先のリポジトリやデフォルトタスク（cleanなど）を定義されている


### build.gradle（appなどのmodule直下）
モジュール（アプリケーション）のビルド設定を記載する。
android sdkの設定、アプリの依存関係を定義する。

#### android sdkの設定
AndroidStudioでプロジェクトを作るとたいていの設定は自動で入れてくれる。

- compileSDKversion
    - コンパイルに使うSDK
- targetSDKversion
    - アプリがターゲットにするSDK。対象とするAndroidがよりversionが高いSDKを持っていてもtargetにしたSDKを使うようになる。
    - 主にversionの上昇によるUI変更を抑える目的で設定する
- minSDKversion
    - 動作保証をする最低versionのSDK。ここで設定したSDKがサポートしていないAPIは使えない。
        - そういったものをどうしても使用したい場合はminSDKversionを上げるか、SDKレベルが低い場合で分岐するコードを書く必要がる。
- versionCode, versionName
    - アプリのバージョン、versionNameがアプリ内で表示されるバージョンになる
- build type
    - リリースビルドとデバックビルド、独自のビルドを設定できる。
    - ビルドによってAPIレベルを変えたりなどが可能。

#### ライブラリの依存関係
```
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'

    testImplementation 'junit:junit:4.12'
    testImplementation 'org.mockito:mockito-core:2.28.2'

    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    androidTestUtil 'androidx.test:orchestrator:1.2.0'
}
```

公開されているものはGroupID:ArtifactID:Versionで指定する。
テスト時、エミュレーターテスト時などで依存を変えれる。

### AndroidManifest.xml
AndroidビルドやAndroid OSはこのファイルからmoduleの諸情報を判断する。
詳細は以下。
https://developer.android.com/guide/topics/manifest/manifest-intro?hl=ja

上記リンクの内容をざっくりと以下で説明する。

```
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-feature android:name="android.hardware.microphone" android:required="true" />

</manifest>
```

#### `<application>`
アプリケーションの諸情報。
アプリ名（`android:label`）、アイコン画像（`android:icon`）、使用する画面のアクティビティの宣言（`<activity android:name=".MainActivity">`）などを行う。
なお、固定文字列や画像などの静的リソースは、/app/resに格納されており、特定の記述で参照できる。

##### `<activity android:name=".MainActivity"/>`
アプリケーションに含まれるアクティビティ（1画面の振る舞い）の宣言と、そのアクティビティが持つインテント（パラメータのようなもの）を定義する。
ここで宣言されていないアクティビティはアプリケーションで利用できない。

上記例では、
`<category android:name="android.intent.category.LAUNCHER" />`
でランチャーから起動した場合の初期画面であることを定義していると共に、
`<action android:name="android.intent.action.MAIN" />`
で起動方法を問わず（例えば他のアプリから起動された場合などでも）起動時の初期画面になりうることを定義している。

#### `<uses-permission>`
アプリが要求する機能の権限。その権限がない場合は動作が制限される。
音声でも操作できるけど画面で操作してもいい、とかの時、マイクの権限があるかどうかで機能を制限したりできる。

#### `<uses-feature>`
アプリに必要な機能。その機能が端末上にない場合はインストールができない。


## 静的リソースの構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445910/ad32af1d-dccf-f286-bb38-92cf5e33fdde.png)

resディレクトリの中に静的リソースを置く。
デフォルトで用意されているのは以下の4つ。

- drawable
    - 主にアプリ内で表示する画像の配置場所
- layout
    - アクティビティの画面xmlを配置場所
- mipmap
    - ランチャーアイコン画像の配置場所
- values
    - 色情報、文字列情報、画面共通の基本スタイルなどの配置場所

機能的には上記の配置ルールは必ずしも絶対ではないが、一般的にはこのようなルールで配置する。

### 画像の配置場所が2つある？？
上記で、`drawable`と`mipmap`は両方画像を置く場所とされている。
この2つは、画像サイズの判定方法に違いがある。
スマホ端末はそれぞれ画面のサイズが違うため、表示すべき画像やアイコンのサイズを端末に合わせて変えたい。
推奨される方法としては、複数サイズの画像を用意して適切な種類の画像を表示する方法になるが、この選び方の違いになる
`drawable`は端末のサイズから表示する画像を決定する
`mipmap`は拡大・縮小処理を経た実際の描画サイズから表示する画像を決定する

ランチャーアイコンは端末側で拡大縮小を行う場合があるため`mipmap`に、アプリ内で表示する画像は自身で決めれるので`drawable`に置く。

ただし`mipmap`はminSDK17以降でないと使用できない

## 画面のテーマの設定方法
どんな画面レイアウトにするか、そのテーマ（ページ全体の見た目）をvalue/style.xmlで設定できる

parentで基本のレイアウトとなるテーマ（これは提供されている）を定義し
テーマが持っているitemを上書きすることで一部を自分好みに適応できる。
詳細はスコープ外なので割愛。

```
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
```

## テストライブラリ

appのbuild.gradleでテストの依存関係を定義する

```
dependencies {
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}
```

`test~~`はローカル単体テスト用で、jvmで実行されandroidに依存しない。主にDBやAPI呼び出しなどを確認する。
`androidtest~~`はInstrumentationテストで、ハードデバイスまたはエミュレータで実行され、Androidに依存する。AndroidUIを含めたテストになる

同時に、testInstrumentationRunnerも設定する

```
android{
    defaultConfig {
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
}
```

これで最低限のテスト環境ができたととになる

### テストでおすすめのライブラリ

#### mockito
指定した値を返すモッククラスを作成することにより、他クラスに依存しないUnitTestにできる。

```
testImplementation 'org.mockito:mockito-cor:2.28.2'
```
```
Android{
    testOptions {
        unitTests.returnDefaultValues = true
    }
}
```


### Robolectrics
androidtestではなくtest(jvm上)でUIなどのテストができるようになる。
`testImplementation 'org.robolectric:robolectric:【VERSION】'`を定義して、
その他`androidx.test.ext:junit`などのandroidtestで依存しているイブラリを同様にtest依存させることで、
全て同じソースでjvm上でもエミュ上でもテストができるようになる。


ほかにもいっぱいあるんだろうけど、今回はこれだけ。

#まとめ
これでひとまずの開発準備は整ったのではなかろうか。
山も谷もない内容だが、Androidアプリ開発の助けになれば幸い。