Flutter mobile_scanner ビルド時の注意点

# はじめに

はじめまして、株式会社コズム開発部の穴澤です。

弊社開発部ではエンジニア組織のさらなる活性化のため、テックブログを開始する運びとなりました。先週の弊社CTO内藤による投稿を皮切りに開発部メンバーで今後もたくさん記事を投稿していく所存ですので読んでいただければ幸いです。

私は以前開発でFlutterのプラグインであるmobile_scannerを使用したのですが、ビルド時にいくつかエラーに遭遇したので、今回はその際の回避法・注意点をまとめてみました。

## 使用したライブラリ

- Dart
    - v3.3.4
- Flutter
    - v3.19.6
- mobile_scanner
    - v4.0.1

# エラー詳細

## 1. ビルド時に遭遇したプラグインのエラー

### 概要

mobile_scannerプラグインが要求する最小SDKバージョンが21であるのに対し、プロジェクトのminSdkVersionが19に設定されているため、ビルドが失敗している。

### エラー文

```bash
/Users/ユーザー名/プロジェクトのパス/android/app/src/debug/AndroidManifest.xml Error:
        uses-sdk:minSdkVersion 19 cannot be smaller than version 21 declared in library [:mobile_scanner] /Users/ユーザー名/プロジェクトのパス/build/mobile_scanner/intermediates/merged_manifest/debug/AndroidManifest.xml as the library might be using APIs not available in 19
        Suggestion: use a compatible library with a minSdk of at most 19,
                or increase this project's minSdk version to at least 21,
                or use tools:overrideLibrary="dev.steenbakker.mobile_scanner" to force usage (may lead to runtime failures)
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:processDebugMainManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 19 cannot be smaller than version 21 declared in library [:mobile_scanner] /Users/ユーザー名/プロジェクトのパス/build/mobile_scanner/intermediates/merged_manifest/debug/AndroidManifest.xml as the library might be using APIs not available in 19
        Suggestion: use a compatible library with a minSdk of at most 19,
                or increase this project's minSdk version to at least 21,
                or use tools:overrideLibrary="dev.steenbakker.mobile_scanner" to force usage (may lead to runtime failures)
```

## 2. Androidビルド時に遭遇したエラー

### 概要

>2-1. 異なるバージョンのKotlin標準ライブラリがプロジェクトに含まれていた

プロジェクト内で複数の依存関係から同じクラスが見つかったことを示している。具体的には、kotlin-stdlib、kotlin-stdlib-jdk7、およびkotlin-stdlib-jdk8の間で重複が発生している。

>2-2. プロジェクトのGradle設定でリポジトリが適切に定義されていない

Gradleがorg.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22の依存関係を解決できないことを示している。Gradleは、依存関係をダウンロードするためにリポジトリの定義が必要である。

### エラー文

<details><summary> 2-1. 異なるバージョンのKotlin標準ライブラリがプロジェクトに含まれていた</summary>

```bash
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:checkDebugDuplicateClasses'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
   > Duplicate class kotlin.collections.jdk8.CollectionsJDK8Kt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.internal.jdk7.JDK7PlatformImplementations found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.internal.jdk7.JDK7PlatformImplementations$ReflectSdkVersion found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.internal.jdk8.JDK8PlatformImplementations found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.internal.jdk8.JDK8PlatformImplementations$ReflectSdkVersion found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.io.path.DirectoryEntriesReader found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.ExperimentalPathApi found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.FileVisitorBuilder found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.FileVisitorBuilderImpl found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.FileVisitorImpl found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.LinkFollowing found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathNode found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathRelativizer found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathTreeWalk found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathTreeWalk$dfsIterator$1 found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathTreeWalkKt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathWalkOption found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathsKt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathsKt__PathReadWriteKt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.io.path.PathsKt__PathUtilsKt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.jdk7.AutoCloseableKt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk7-1.7.22 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22)
     Duplicate class kotlin.jvm.jdk8.JvmRepeatableKt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.jvm.optionals.OptionalsKt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10
     Duplicate class kotlin.random.jdk8.PlatformThreadLocalRandom found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.streams.jdk8.StreamsKt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.streams.jdk8.StreamsKt$asSequence$$inlined$Sequence$1 found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.streams.jdk8.StreamsKt$asSequence$$inlined$Sequence$2 found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.streams.jdk8.StreamsKt$asSequence$$inlined$Sequence$3 found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.streams.jdk8.StreamsKt$asSequence$$inlined$Sequence$4 found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.text.jdk8.RegexExtensionsJDK8Kt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Duplicate class kotlin.time.jdk8.DurationConversionsJDK8Kt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.7.10 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10)
     Go to the documentation to learn how to <a href="d.android.com/r/tools/classpath-sync-errors">Fix dependency resolution errors</a>.
```
</details>

<details><summary> 2-2. プロジェクトのGradle設定でリポジトリが適切に定義されていない</summary>

```bash
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring root project 'android'.
> Could not resolve all files for configuration ':classpath'.
   > Cannot resolve external dependency org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22 because no repositories are defined.
     Required by:
         project :
```
</details>

## 3. iOSビルド時に遭遇したエラー

### 概要

アプリがカメラへのアクセスを試みた際に、ユーザーのプライバシーに関する説明がInfo.plistに含まれていないためにクラッシュしたことを示している。iOSでは、カメラやマイクなどのプライバシーに敏感なデータにアクセスする際には、ユーザーにその使用目的を説明する必要がある。

### エラー文

```bash
[access] This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
```

# 解決方法

## 1. ビルド時に遭遇したプラグインのエラー

>1. android / app / build.gradle を変更
    
```diff_groovy
android {
    defaultConfig {
- minSdkVersion flutter.minSdkVersion
+ minSdkVersion 21
    }
}
```

2\. flutter clean を実行
3\. flutter pub get を実行

## 2. Androidビルド時に遭遇したエラー

>1. android / build.gradle に追記
    
```groovy
buildscript {
    repositories {
        google()
        mavenCentral()
    }
    ext.kotlin_version = '1.8.22' // Kotlinの最新バージョンを記述
    dependencies {
        classpath 'com.android.tools.build:gradle:7.0.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
```
    
>2\. android / app / build.gradle に追記
    
```groovy
configurations.all {
    resolutionStrategy.force 'org.jetbrains.kotlin:kotlin-stdlib:1.8.22'
    resolutionStrategy.force 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22'
    resolutionStrategy.force 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22'
}
```
    
3\. flutter clean を実行
4\. flutter pub get を実行

## 3. iOSビルド時に遭遇したエラー

>ios / Runner / Info.plist のdict内に追記

```xml
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) needs camera access.</string>
```

# おわりに

Flutterはマルチプラットフォームにビルドできるという利点があるものの、ビルドする際にそれぞれ異なる注意点があるため、留意しなければならないと感じました。

このようなconfig系は知識が重要です。
このような場をお借りしてエラー原因やリサーチして解決した手順を共有できるため、この記事が他の方々の助けになれば幸いです。