shinonome-inc / qiita_client_yo

【模擬開発案件】Qiitaクライアントアプリ(PlayGroundモバイルコース最終課題)
3 stars 0 forks source link

カメラ勉強会メモ #39

Closed KobayashiYoh closed 1 year ago

KobayashiYoh commented 2 years ago

第1回「ImagePicker」

ImagePickerってなに?

ImagePickerとは、Flutterでカメラや画像を利用するためのパッケージです。 ImagePickerを使用することでデバイスのカメラを起動したり、アルバムを開いたりすることができます。 また、カメラで撮った写真やアルバムから選択した画像を画面に表示することも可能です。 今回はカメラとアルバムを開くのをゴールとします。

公式ドキュメント

https://pub.dev/packages/image_picker

インストール

iOS・Android共通

それでは、さっそくImagePickerをインストールしていきます。 まず、flutter pub add image_pickerをコマンドで叩く or pubspec.yamlのdependencies:にimage_picker: ^0.8.4+11を追加してImagePickerをインストールします。 インストールが終わったら、flutter pub getをコマンドで叩く or pub getボタンをクリックしてください。

普通のパッケージならこの段階で使用できるようになりますが、ImagePickerだとそうはいきません。 パーミッション(カメラやアルバムなどを使用する許可)をデバイスに与えてあげなければいけないのです。 パーミッションをデバイスに与える方法はiOSとAndroidによって異なるため、それぞれ個別に紹介していきます。

iOS編

まず、ios/Runner/Info.plisetを開いてください。 Info.plisetを開いてファイルを一番下までスクロールすると、このような記述があります。

    </array>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
</dict>
</plist>

この との間に与えたいパーミッションを追加で記述していきます。 アルバムへのアクセスを求めるNSPhotoLibraryUsageDescriptionとカメラへのアクセスを求めるNSCameraUsageDescription、マイクへのアクセスを求めるNSMicrophoneUsageDescription(今回は使いませんがビデオ撮影をする際に必要です)を追加します。 こんな感じで記述できればOKです。

    </array>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>このアプリが"写真"へのアクセスを求めています</string>
    <key>NSCameraUsageDescription</key>
    <string>このアプリが"カメラ"へのアクセスを求めています</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>このアプリが"マイク"へのアクセスを求めています</string>
</dict>
</plist>

Android編

今回は不要です。


サンプルコード

import 'dart:io';

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Image Picker App',
      theme: ThemeData.dark(),
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  XFile? _imageFile;
  final ImagePicker _picker = ImagePicker();

  Future<void> _selectImage(ImageSource source) async {
    // ImageSource.cameraでカメラ起動
    // ImageSource.galleryでアルバム開く
    final pickedFile = await _picker.pickImage(source: source);
    if (pickedFile != null) {
      setState(() {
        _imageFile = XFile(pickedFile.path);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          if (_imageFile == null) Center(child: const Text('ここに写真を表示')),
          if (_imageFile != null) Image.file(File(_imageFile!.path)),
        ],
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          FloatingActionButton(
            onPressed: () {
              _selectImage(ImageSource.camera);
            },
            child: const Icon(Icons.camera_alt_outlined),
          ),
          const SizedBox(height: 16.0),
          FloatingActionButton(
            onPressed: () {
              _selectImage(ImageSource.gallery);
            },
            child: const Icon(Icons.photo_library_outlined),
          ),
        ],
      ),
    );
  }
}
KobayashiYoh commented 2 years ago

第2回「gallery_saver」

gallery_saverってなに?

gallery_saverとは、Flutterで画像をアルバムに保存するためのパッケージです。 これを使えば、第1回で紹介したimage_pickerで撮影した写真をアルバムに保存することができます。 第1回で作成したflutterプロジェクトをそのまま使用すると楽です。

公式ドキュメント

https://pub.dev/packages/gallery_saver

インストール

iOS・Android共通

まず、pubspec.yamlのdependencies:gallery_saver: ^2.3.2を追加します(flutter pub add gallery_saverでも可)。 次に、pub getボタンをクリックします(flutter pub getでも可)。 ここまで終わったら、image_pickerと同様にパーミッションを追加します。

iOS編

今回はアルバムを使用するのでNSPhotoLibraryUsageDescriptionを記述していきます。 しかし、第1回で使用したFlutterプロジェクトをそのまま使用する場合、既にパーミッションが追加されているので、新たに追加する必要はありません。 それ以外の場合はios/Runner/Info.plisetにNSPhotoLibraryUsageDescriptionを追加してください。 詳しい方法は第1回の資料を参照してください。

Android編

まず、android.permission.WRITE_EXTERNAL_STORAGEと呼ばれるパーミッションを追加します。 android/app/src/main/AndroidManifest.xmlを開き、上から2行目と3行目の間に<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />を下記のように追加します。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.image_picker_camera">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <application
        android:label="image_picker_camera"

公式ドキュメントだとここまでしか説明がないのですが、このままだと恐らくminSdkVersionに関するエラーが出てくると思います。 android/app/build.gradleを開き、デフォルトの値から21以上の値に変更しましょう。

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.image_picker_camera"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

これでもまだエラーが表示されること場合あります。ext.kotlin_versionに関するエラーです。 これを解決するには、android/build.gradleの上から2行目にあるext.kotlin_versionを変更する必要があります。 '1.5.10’ぐらいに設定しておけば問題なく実行できると思います。

buildscript {
    ext.kotlin_version = '1.5.10'
    repositories {
        google()
        jcenter()
    }

サンプルコード

import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:image_picker/image_picker.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Image Picker App',
      theme: ThemeData(
        brightness: Brightness.dark,
        floatingActionButtonTheme: FloatingActionButtonThemeData(
          backgroundColor: Colors.blue[500],
        ),
      ),
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  XFile? _imageFile;
  final ImagePicker _picker = ImagePicker();

  Future<void> _selectImageFromDevice(ImageSource source) async {
    final pickedFile = await _picker.pickImage(source: source);
    if (pickedFile == null) {
      return;
    }
    if (source == ImageSource.camera) {
      GallerySaver.saveImage(pickedFile.path);
    }
    setState(() {
      _imageFile = XFile(pickedFile.path);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          if (_imageFile == null) Center(child: const Text('ここに写真を表示')),
          if (_imageFile != null) Image.file(File(_imageFile!.path)),
        ],
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          FloatingActionButton(
            onPressed: () {
              _selectImageFromDevice(ImageSource.camera);
            },
            child: const Icon(Icons.camera_alt_outlined),
          ),
          const SizedBox(height: 16.0),
          FloatingActionButton(
            onPressed: () {
              _selectImageFromDevice(ImageSource.gallery);
            },
            child: const Icon(Icons.photo_library_outlined),
          ),
        ],
      ),
    );
  }
}
KobayashiYoh commented 2 years ago

第3回「camera」

cameraってなに?

cameraとは、名前の通りカメラのFlutterパッケージです。 image_pickerより複雑ですが、その分できることも多いです。 image_pickerでは、デバイスのカメラを起動するだけでした。 しかし、cameraでは、自分の実装で写真を撮影したり、内カメラと外カメラに切り替えたりすることができるため、自由度の高いオリジナルのカメラアプリを作成することができます。 とはいえ、この説明ではあまりピンと来ないと思うので、実際に自分の手を動かしながらcameraについて学んでいきましょう。 今回は新規Flutterプロジェクトを作成し、そこでcameraパッケージを使ってみましょう。


公式ドキュメント

https://pub.dev/packages/camera

インストール

iOS・Android共通

まず、pubspec.yamlのdependencies:camera を追加します。 次に、pub getボタンをクリックします(flutter pub getでも可)。 ここまで終わったら、これまでと同様にパーミッションを追加します。

iOS編

ios/Runner/Info.plistに次の4行を追加してください。

<key>NSCameraUsageDescription</key>
<string>your usage description here</string>
<key>NSMicrophoneUsageDescription</key>
<string>your usage description here</string>

Android編

android/app/build.gradleを次のように設定してください。21以上ならOKです。 minSdkVersion 21


サンプルコード

import 'dart:async';

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

late List<CameraDescription> cameras;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  cameras = await availableCameras();
  runApp(const CameraApp());
}

class CameraApp extends StatefulWidget {
  const CameraApp({Key? key}) : super(key: key);

  @override
  _CameraAppState createState() => _CameraAppState();
}

class _CameraAppState extends State<CameraApp> {
  late CameraController controller;

  @override
  void initState() {
    super.initState();
    controller = CameraController(cameras[0], ResolutionPreset.max);
    controller.initialize().then((_) {
      if (!mounted) {
        return;
      }
      setState(() {});
    });
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (!controller.value.isInitialized) {
      return Container();
    }
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: CameraPreview(controller),
    );
  }
}
KobayashiYoh commented 2 years ago

第n回「」

ってなに?


公式ドキュメント


インストール

iOS・Android共通

iOS編

Android編


サンプルコード