🚀 ニフティ’s Notion

Androidアプリ開発入門#3

第3章 Androidプロジェクト

3.1 Gradle
image block

Java用のビルドツールには有名なものとして

がありますが、Androidではこのうち最も新しいGradleを採用しています。

Icon
Gradleはコマンドラインから実行でき、Javaさえあれば動作します。
Android Studioがなくても以下のようにしてビルドが可能です。
Windows
gradlew.bat installRelease
mac/Linux
./gradlew installRelease

(再掲)

image block

Gradleは上図の②にあたり、ソースコードやビルドバリアント、ライブラリ、リソースなどを配布するための形式にビルドします。

3.2 プロジェクト構成
image block

Android Studioの左側にあるプロジェクト部分を見てみましょう。

現在のファイル一覧が見えています。 

デフォルトでは「Android」という表示形式になっていて、Android用に見やすく整理して表示するようになっています。 
実際のディレクトリ構造を確認するため、左上の「Android」をクリックし、「Project」に切り替えてみましょう。

image block
PROJECT
├── gradle/
├── build.gradle                       -> Gradle設定(プロジェクト全体) ...①
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── settings.gradle                    -> Gradleモジュールロード設定
└── app/                               -> appモジュール
    ├── build.gradle                   -> Gradle設定(モジュール) ...②
    ├── libs/
    ├── proguard-rules.pro
    └── src/                           -> ソース
  • Gradleのマルチモジュール開発用の構成がデフォルトになっています
    • 共通の依存関係や設定を上位(①)におき、プロジェクト毎の設定を個別(②)にできます
      ()
      root
      ├── build.gradle
      ├── app1
      |   └── build.gradle
      └── app2
          └── build.gradle
  • モジュールを増やしていくことで、ライブラリや別バージョンのアプリを一括で管理できます
    • アプリを1つ開発するだけなら、app/srcの中にソースコードを置いていくだけでできます
    • バージョンカタログを使うことで、複数のモジュール間の依存ライブラリを簡単に管理できます

3.2.1 app/build.gradle

app/build.gradle を開いてみましょう。

ここでは、バージョン設定の値を指定することができます。

image block
android {
    namespace 'com.example.strongestnews'
    compileSdk 33

    defaultConfig {
        applicationId "com.example.strongestnews"
        minSdk 24
        targetSdk 33
        versionCode 1
        versionName "1.0"
				...
    }
		...
}
...
app/build.gradle
3.2.2 アプリケーションID

app/build.gradle に applicationId という設定項目があります。

アプリケーションIDの目的と特徴には以下があります。

  • デバイスとGooglePlayStoreで アプリが一意に識別されるためのID
  • デフォルトでセットアップ時に選択したパッケージ名が自動的に割り当てられる
    • パッケージ名と分けることはできるが、非推奨
    • パッケージ名とアプリケーションIDが一致するようにしておく
  • アプリの公開後はアプリケーションIDを変更しないこと
    • 変更すると、別アプリとして扱われる

3.2.3 バージョニング

app/build.gradle の defaultConfig 内には versionCode versionName という設定項目があります。

これらは以下の違いがあります。

  • versionCode
    • 内部バージョン番号
    • ユーザーに表示される番号ではなく、内部で新旧を判断するために使われる
  • versionName
    • ユーザーに表示されるバージョン番号として使用される文字列

3.3 ソースコード構成

基本的にソースコードはmainの下に置きます。

src
├── androidTest/
│   └── java/
├── main/
│   ├── java/                          -> ソースコード...①
│   ├── res/                           -> リソース...②
│   └── AndroidManifest.xml            -> マニフェストファイル...③
└── test/
    └── java/
3.3.1 ① java/
  • 文字通りJavaソースコードを置く
  • Kotlinであってもここに置く
  • パッケージ名によってディレクトリを切っていく必要がある(Javaの文法規則)
image block
3.3.2 Kotlinソースコード

MainActivity.ktを開いてみましょう。

package com.example.strongestnews

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.strongestnews.ui.theme.StrongestNewsTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            StrongestNewsTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting("Android")
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    StrongestNewsTheme {
        Greeting("Android")
    }
}
src/main/java/com.example.strongestnews/MainActivity.kt

MainActivityは、ComponentActivityを継承したクラスであることがわかります。

今回はJetpack ComposeというUIツールキットを用いるため、ComponentActivityを継承しているのです。

onCreate()がオーバーライドされ、setContent()でComposable関数を呼び出しています。

…が、取り敢えず今はそういうものだと思っておいてください。

右上の「Split」を選択します。

image block

「Build & Refresh…」と表示されるので、ポチッと押します。

しばらくすると、Previewアノテーションのあるコンポーザブルをエディタ上でプレビュー確認できるようになりました。

Icon
ポイント
  • プレビュー表示にはBuildが必要
  • Composable関数を分割したときなど要素ごとに見た目を確認するのに役立つ
Icon
Android Studio右下の「Gradle Build Running…」と表示されている場所でビルドなど各処理の状況を見ることができます。気長に待ちましょう。
3.3.3 Theme

アプリの見た目に関する設定を行います。

image block

  • アプリ共通のカラーパレットや文字サイズなどをここで設定する
  • ダークモードのカラー定義などもここで行う
3.3.4 ② Resource

res/ 以下に格納されているものを見てみましょう。

アプリ内で利用する画像、レイアウト定義、色定義などはリソースとして管理されます。

これらは決まったディレクトリに設置する必要があります。

image block
新規作成プロジェクトのリソース
image block
成熟してきたプロジェクトのリソース

resにリソースを追加したい場合、左タブのResourceManagerから追加することが可能です。

image block

例. Resourceに追加したものを使いたい

Resourceに追加したものはIDで参照できるようになります。

  • XMLから参照する

    「@種類/名前」で参照することができます。

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/hoge" />
  • コードから参照する
    • IDを管理する「R」クラスが自動生成される
    • 「R.{種類}.{名前}」でIDが取得できるので、IDを引数にとるメソッドに渡す。
    • Jetpack Composeでも「R.{種類}.{名前}」でIDが取得
    // すでに画面に配置されている要素を探すときは"R.id"を使う
    // ex) IDがmyimageviewである要素を探す
    val imageView = findViewById(R.id.myimageview);
    
    // リソースから取得する場合は"R.{種類}"で探す
    // ex) myimageを画像としてセットする
    imageView.setImageResource(R.drawable.myimage);

Icon
リソースフォルダはハイフン区切りで情報を加え、フォルダを分けることが可能です。付加した情報により、使われるリソースが自動で切り替わります。

例. サフィックスをつけて使われるリソースを自動で切り替える

res/
├── drawable-xxxhdpi/
│   └── some_image.png
├── drawable-xxhdpi/
│   └── some_image.png
├── drawable-xhdpi/
│   └── some_image.png
├── drawable-hdpi/
│   └── some_image.png
└── drawable-mdpi/
    └── some_image.png
サブディレクトリ名 用途
drawable-ldpi
drawable-mdpi
drawable-hdpi
drawable-xhdpi
drawable-xxhdpi
drawable-xxxhdpi
drawable-nodpi
画面解像度(DPI)によって使用する画像ファイルを切り替える。各DPIの具体的な値は 公式ガイド を参照。
全部用意する必要はなく、一番近い解像度のものから拡大・縮小されて使用される。
nodpiはベクタ画像用。
layout-sw{N}dp
layout-w{N}dp
layout-h{N}dp
幅が{N}dp以上の場合に選択されるレイアウト。タブレットの場合にレイアウトを変更する、というような場合に使う。
values-ja
values-en
values-cn
              など
言語ごとに表示する文字を切り替えるような場合に使う。いわゆる多言語対応。
3.3.5 ③ AndroidManifest.xml

コンポーネントがIntentを受け取るためには、アプリが何のコンポーネントを持っていて、どんな種類のIntentを受け付けられるのか、OSに教える必要があります。その役割を担うファイルがAndroidManifest.xmlです。

マニフェストはそれ以外にも以下のように様々なことを行います。

  • アプリのコンポーネントを宣言
  • アプリに必要な権限を識別
  • アプリが使用するAPIに基づいて、必要とする最小APIレベルを宣言
  • アプリで必要とされるハード/ソフトウェア機能(カメラ、Bluetooth、etc…)を宣言
  • アプリにリンクする必要のあるAPIライブラリ(Google mapライブラリなど)を宣言

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

    <!-- アプリケーション定義 -->
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.StrongestNews"
        tools:targetApi="31">
        <!-- Activity定義 -->
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.StrongestNews">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

このファイルは、OSに以下のようなことを伝えています。

  • xmlns:android
    • Androidネームスペースを定義
    • Android用のxmlファイルであることを宣言
  • <application>
    • <manifest>内に1つだけある
  • <activity>
    • <application>内に1つだけある
    • android:nameとして ".MainActivity"が設定されている
      • 今回のアプリにはActivityが1つだけ存在し、MainActivityというクラス名である
      • 1つしかないので、このActivityが起動時に開かれる
  • <intent-filter>
    • <intent-filter>内に<action>と<category>が設定されている
      • このActivityは、起動Intent( action.MAIN かつ category.LAUNCHER )を受け取ることができる

アプリの動作要件によっては以下の情報を追加します。

<uses-permission>

セキュリティの観点から、アプリの使える機能は強く制限されています。

  • インターネット通信
  • SMSへのアクセス
  • カメラへのアクセス

などの機能を使う場合はここに記述し、ユーザの許可( パーミッション )を得るようになっています。 ユーザの許諾を得る ことでようやく動作できる、というのがアプリの基本であり理念です。

ex) インターネットアクセス

<uses-permission android:name="android.permission.INTERNET" />
Icon
Android 5.1まで、全てのパーミッションの確認はインストール時に行われていました。しかし大半のユーザが確認もせず許可するため、無意味になっていました。
image block

Android 6.0からは確認方法を見直し、一部の重要なパーミッションは 実行時 に、 最初に権限が必要になった時 に確認を行うようになりました。また、インターネット通信などほぼ全てのアプリで使う権限については、確認を行わないようになりました。(AndroidManifest.xmlへの記載は必要です)

image block

<uses-feature>

アプリ動作に特定の機能が必須の場合、ハードウェアによってはその機能がない場合があります。特定機能がないデバイスにはインストールできないようにするため、必要な機能を宣言することができます。

ex) コンパスを必須とする

<uses-feature android:name="android.hardware.sensor.compass"
                  android:required="true" />