第3章 Androidプロジェクト
3.1 Gradle
Java用のビルドツールには有名なものとして
がありますが、Androidではこのうち最も新しいGradleを採用しています。
(再掲)
Gradleは上図の②にあたり、ソースコードやビルドバリアント、ライブラリ、リソースなどを配布するための形式にビルドします。
3.2 プロジェクト構成
Android Studioの左側にあるプロジェクト部分を見てみましょう。
現在のファイル一覧が見えています。
デフォルトでは「Android」という表示形式になっていて、Android用に見やすく整理して表示するようになっています。
実際のディレクトリ構造を確認するため、左上の「Android」をクリックし、「Project」に切り替えてみましょう。
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 を開いてみましょう。
ここでは、バージョン設定の値を指定することができます。
android {
namespace 'com.example.strongestnews'
compileSdk 33
defaultConfig {
applicationId "com.example.strongestnews"
minSdk 24
targetSdk 33
versionCode 1
versionName "1.0"
...
}
...
}
...
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の文法規則)
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")
}
}
MainActivityは、ComponentActivityを継承したクラスであることがわかります。
今回はJetpack ComposeというUIツールキットを用いるため、ComponentActivityを継承しているのです。
onCreate()がオーバーライドされ、setContent()でComposable関数を呼び出しています。
…が、取り敢えず今はそういうものだと思っておいてください。
右上の「Split」を選択します。
「Build & Refresh…」と表示されるので、ポチッと押します。
しばらくすると、Previewアノテーションのあるコンポーザブルをエディタ上でプレビュー確認できるようになりました。
- プレビュー表示にはBuildが必要
- Composable関数を分割したときなど要素ごとに見た目を確認するのに役立つ
3.3.3 Theme
アプリの見た目に関する設定を行います。
- アプリ共通のカラーパレットや文字サイズなどをここで設定する
- ダークモードのカラー定義などもここで行う
3.3.4 ② Resource
res/ 以下に格納されているものを見てみましょう。
アプリ内で利用する画像、レイアウト定義、色定義などはリソースとして管理されます。
これらは決まったディレクトリに設置する必要があります。
resにリソースを追加したい場合、左タブのResourceManagerから追加することが可能です。
例. 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);
例. サフィックスをつけて使われるリソースを自動で切り替える
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 )を受け取ることができる
-
<intent-filter>内に<action>と<category>が設定されている
アプリの動作要件によっては以下の情報を追加します。
<uses-permission>
セキュリティの観点から、アプリの使える機能は強く制限されています。
- インターネット通信
- SMSへのアクセス
- カメラへのアクセス
などの機能を使う場合はここに記述し、ユーザの許可( パーミッション )を得るようになっています。 ユーザの許諾を得る ことでようやく動作できる、というのがアプリの基本であり理念です。
ex) インターネットアクセス
<uses-permission android:name="android.permission.INTERNET" />
Android 6.0からは確認方法を見直し、一部の重要なパーミッションは 実行時 に、 最初に権限が必要になった時 に確認を行うようになりました。また、インターネット通信などほぼ全てのアプリで使う権限については、確認を行わないようになりました。(AndroidManifest.xmlへの記載は必要です)
<uses-feature>
アプリ動作に特定の機能が必須の場合、ハードウェアによってはその機能がない場合があります。特定機能がないデバイスにはインストールできないようにするため、必要な機能を宣言することができます。
ex) コンパスを必須とする
<uses-feature android:name="android.hardware.sensor.compass"
android:required="true" />