Chapter 11

  Flutterプロジェクトの中身

heyhey1028
heyhey1028
2023.02.17に更新

前章の終わりに Flutter プロジェクトを作成しました。今回はその中身がどのようなディレクトリ構成になっているのか、また沢山あるファイルの中でよく使うファイルとその用途を簡単に解説していきます。

ディレクトリ構成

前章のflutter createコマンドで以下のようなディレクトリ構成のプロジェクトが作成されたかと思います。

.
├── README.md
├── analysis_options.yaml
├── android
├── ios
├── lib
│   └── main.dart
├── linux
├── macos
├── pubspec.lock
├── pubspec.yaml
├── test
├── test_flutter.iml
├── web
└── windows

libディレクトリ

実際のアプリのコードを記述していくディレクトリです。libディレクトリ内にある main.dartというファイルが Flutter アプリのエントリーポイントとなるファイルになります。

analysis_options.yamlファイル

analisys_options.yaml は Dart のコードを解析する際の設定ファイルです。Flutter のコードを解析する際にはこのファイルの設定を参照します。

Platform ごとのディレクトリ

iosandroidwebmacoslinuxwindows はそれぞれ Platform ごとのディレクトリです。libディレクトリに記述されたコードを各種 platform に対応したコードに変換する際に参照されます。

パッケージ管理ファイル

pubspec.yamlpubspec.lock は Flutter のパッケージ管理に関するファイルです。pubspec.yamlにはパッケージの依存関係を記述し、pubspec.lockにはその依存関係を解決した結果が記述されます。

javascript などで言うところのpackage.jsonpackage-lock.jsonに近いですね。

testディレクトリ

お察しの通り、Flutter のテストコードを記述するディレクトリです。

その他

[プロジェクト名].imlとなっているファイルは 開発に IntelliJ IDEA を使う際に必要なファイルです。

ファイルの中身

全ては紹介できませんが、一部よく使うファイルについてだけ軽くご紹介させていただきます。

main.dart

main.dartは前述の通り、アプリのエントリーポイントとなるファイルです。

特に指定がなければflutter runを実行するとこのファイルが実行されます。こちらのファイルの中身についてはまた後ほど詳しく見ていきます。

main.dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

pubspec.yaml

pubspec.yamlは プリケーションのバージョン管理や依存パッケージの管理などアプリケーションに関する設定を記述するファイルです。

前章で紹介したflutter pub addで依存パッケージをインストールするとこのファイル内のdependenciesに追記されます。

また画像などのアセットファイルを追加する際もこのファイル内のflutter以下にアセットファイルのパスを記述することでアクセスできるようになります。

pubspec.yaml
name: test_flutter
description: A new Flutter project.

publish_to: "none"

version: 1.0.0+1

environment:
  sdk: ">=2.17.6 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true
+ assets:
+   - assets/my_icon.png
+   - assets/background.png

ios ディレクトリ内

ios/Runner/AppDelegate.swift

iOS 特有の機能などを使う場合には iOS 側に処理の実装が必要な場合があります。その場合はこのファイルに実装を記述します。

AppDelegate.swift
import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

ios/Runner/Info.plist

位置情報の取得や BlueTooth の使用などユーザーに許可を求める機能を使う場合などにこのファイルに設定を記述します。

info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleDisplayName</key>
	<string>Test Flutter</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>test_flutter</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>$(FLUTTER_BUILD_NAME)</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>$(FLUTTER_BUILD_NUMBER)</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UIViewControllerBasedStatusBarAppearance</key>
	<false/>
	<key>CADisableMinimumFrameDurationOnPhone</key>
	<true/>
</dict>
</plist>

android ディレクトリ内

android/app/build.gradle

Android のアプリケーションに関する設定ファイルです。コンパイルに使う SDK のバージョンやアプリケーションの設定などを記述します。

使用するパッケージによってはネイティブ側にも依存関係の設定が必要な場合があり、そのような際にはこのファイルに変更を加えることがあります。

app/build.gradle
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.test_flutter"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

android/app/src/main/AndroidManifest.xml

位置情報の取得や BlueTooth の使用などユーザーに許可を求める機能を使う場合などにこのファイルに設定を記述します。

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test_flutter">
   <application
        android:label="test_flutter"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>

まとめ

今回は生成された Flutter プロジェクトの構成とその中でも重要なファイルの役割についてピックアップして説明しました。

次章から早速サンプルアプリの解説!...と行きたいところですが、その前にまず Flutter を理解する上で重要な概念についてご紹介していきたいと思います。