Open13
Ubntsuローカルサーバーを用いてFlutter開発ログ
環境
- 自宅に眠ってたミニデスクトップにubtnsuOSをいれてSSH接続できるようにしている
- WindowsPCがメイン機
目標
- Flutterの開発環境をUbnstuに集約
- QRコードを読み取りデータとして保存するアプリを作成
経緯
- 貯まったアイコスのQRコードをなくしたいため
- Flutterの勉強のため
Fluuterの依存関係をインストール
sudo apt-get update
sudo apt-get install git curl wget unzip xz-utils zip libglu1-mesa
最新のSDKをダウンロード
から最新のバージョンを確認し、wgetで取得
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.24.0-stable.tar.xz
そのあと解凍
tar xf flutter_linux_3.24.0-stable.tar.xz
パスの追加
echo 'export PATH="$PATH:/home/tsukuda/flutter/bin"' >> ~/.bashrc
source ~/.bashrc
動作確認
flutter doctor
これでメッセージがただしくでてたのでインストール完了
doctorのエラーを修正
いくつか失敗していたので修正する
tsukuda@homeserver:~/works/SaveQR$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.0, on Ubuntu 24.04 LTS 6.8.0-35-generic, locale en_US.UTF-8)
[✗] Android toolchain - develop for Android devices
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/to/linux-android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
`flutter config --android-sdk` to update to that location.
[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✗] Linux toolchain - develop for Linux desktop
✗ clang++ is required for Linux development.
It is likely available from your distribution (e.g.: apt install clang), or can be downloaded from https://releases.llvm.org/
✗ CMake is required for Linux development.
It is likely available from your distribution (e.g.: apt install cmake), or can be downloaded from https://cmake.org/download/
✗ ninja is required for Linux development.
It is likely available from your distribution (e.g.: apt install ninja-build), or can be downloaded from https://github.com/ninja-build/ninja/releases
✗ pkg-config is required for Linux development.
It is likely available from your distribution (e.g.: apt install pkg-config), or can be downloaded from https://www.freedesktop.org/wiki/Software/pkg-config/
[!] Android Studio (not installed)
[✓] Connected device (1 available)
[✓] Network resources
! Doctor found issues in 4 categories.
Linux toolchain - develop for Linux desktopの対応
sudo apt-get install clang
sudo apt-get install cmake
sudo apt-get install ninja-build
sudo apt-get install pkg-config
sudo apt-get install libgtk-3-dev
これでエラーは消えた
Android toolchain - develop for Android devices
を参考に対応
# SDKをいれる
sudo apt install android-sdk openjdk-17-jdk
# sudoで利用になるため、ルートに移動
sudo cp -rf /usr/lib/android-sdk ~/
sudo chown -R $(id -u):$(id -g) ~/android-sdk
# toolsをインストール
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
unzip commandlinetools-linux-11076708_latest.zip
mkdir -p ~/android-sdk/cmdline-tools/latest
mv ~/cmdline-tools/* ~/android-sdk/cmdline-tools/latest/
# 設定を変更する
vi ~/.bashrc
source ~/.bashrc
# sdkマネージャーで必要なレベルを入れる
sdkmanager "platform-tools" "platforms;android-29" "build-tools;29.0.3"
# 最後に同意を行っておく
flutter doctor --android-licenses
クロームはなくていい、これでflutterの準備完了
tsukuda@homeserver:~$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.0, on Ubuntu 24.04 LTS 6.8.0-35-generic, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✓] Linux toolchain - develop for Linux desktop
[!] Android Studio (not installed)
[✓] Connected device (1 available)
[✓] Network resources
! Doctor found issues in 2 categories.
flutterのプロジェクト作成
このときフォルダに大文字あって怒られた
flutter create .
稼働するもリモートのため失敗
tsukuda@homeserver:~/works/saveqr$ flutter run
Launching lib/main.dart on Linux in debug mode...
Building Linux application...
✓ Built build/linux/x64/debug/bundle/saveqr
(saveqr:750820): Gtk-WARNING **: 13:23:52.733: cannot open display:
Error waiting for a debug connection: The log reader stopped unexpectedly, or never started.
Error launching application on Linux.
どうやらX11フォワーディング
にてlinuxで表示できないGUIをホスト機に送る必要がある。
にあるパブリックのXmingをインストールしてやってみたがうまくいかず
DISPLAYが空のままになる。
できた人おしえてほしい、、
VcXsrvでやってみる
Select display settings: Multiple windows を選択
Select how to start clients: Start no client を選択
Disable access controlを選択
これでインストールしてxclockが表示されたけど
リモートからはだせなかった
原因
- windows側にいれていたESETが6000ポートをブロックしていた
- export DISPLAY=192.168.68.63:0.0
- にて、PCのIPを直接してしたらいけた
- ただ普通にSSHしたら描画重かったので
- ssh -YC ○○で接続したら軽くなった
を参考
flutter run
で実行し
r
でホットリロード状態に
QRコードの読み取り
パーミッションの設定
- AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA"/>
- Info.plist
<key>NSCameraUsageDescription</key>
<string>QRコードのスキャンのためにカメラにアクセスします。</string>
まずQRの読み取りに必要なパッケージ追加
flutter pub add qr_code_scanner
次にjava17を利用バージョンに
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
Gradleのバージョン指定
- android/gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
android端末をUSBで接続
- ubntsuを入れたPCのほうにUSBでandroidをつないだ
- 下記コマンドで端末を確認
adb devices
キャッシュをけして、実行
flutter clean
flutter pub get
flutter run
これでQRコードの開発準備ができた
こぴぺ用のパッケージ
flutter pub add qr_code_scanner
読み取った値をコピペできるように
import 'package:flutter/material.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
import 'package:clipboard/clipboard.dart';
import 'dart:io'; // これを追加
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: QRViewExample(),
);
}
}
class QRViewExample extends StatefulWidget {
@override
State<StatefulWidget> createState() => _QRViewExampleState();
}
class _QRViewExampleState extends State<QRViewExample> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
QRViewController? controller;
String? qrText;
@override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
// Platform クラスを使用するために dart:io が必要
controller!.pauseCamera();
}
controller!.resumeCamera();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
flex: 4,
child: QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
),
),
Expanded(
flex: 1,
child: Center(
child: Text(qrText ?? 'スキャンしてQRコードを表示'),
),
),
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(qrText ?? 'スキャンしてQRコードを表示'),
ElevatedButton(
onPressed: () {
if (qrText != null) {
FlutterClipboard.copy(qrText!).then((value) =>
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('クリップボードにコピーしました'))));
}
},
child: Text('コピー'),
),
],
),
),
],
),
);
}
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
setState(() {
qrText = scanData.code;
});
});
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
}
firebaseとの連携
fireabaseのツールインストール
sudo npm install -g firebase-tools
firebaseにログイン
- ブラウザがないので下記の方法
firebase login --no-localhost
cliパッケージを入れる
dart pub global activate flutterfire_cli
export PATH="$PATH":"$HOME/.pub-cache/bin"
source ~/.bashrc
プロジェクトの指定
- androidを選択
flutterfire configure --project=ここにプロジェクトID
パッケージ追加
flutter pub add firebase_core
flutter pub add cloud_firestore
保存を確認
- いったんfirestoreのルールをなしにてテスト
import 'package:flutter/material.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
import 'package:clipboard/clipboard.dart';
import 'package:cloud_firestore/cloud_firestore.dart'; // Firestore をインポート
import 'dart:io'; // これを追加
import 'package:firebase_core/firebase_core.dart'; // Firebase を初期化するために必要
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(); // Firebase を初期化
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: QRViewExample(),
);
}
}
class QRViewExample extends StatefulWidget {
@override
State<StatefulWidget> createState() => _QRViewExampleState();
}
class _QRViewExampleState extends State<QRViewExample> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
QRViewController? controller;
String? qrText;
@override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller!.pauseCamera();
}
controller!.resumeCamera();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
flex: 4,
child: QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
),
),
Expanded(
flex: 1,
child: Center(
child: Text(qrText ?? 'スキャンしてQRコードを表示'),
),
),
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(qrText ?? 'スキャンしてQRコードを表示'),
ElevatedButton(
onPressed: () {
if (qrText != null) {
// クリップボードにコピー
FlutterClipboard.copy(qrText!).then((value) =>
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('クリップボードにコピーしました'))));
// Firebase Firestore に保存
_saveQRCodeToFirestore(qrText!);
}
},
child: Text('コピー & 保存'),
),
],
),
),
],
),
);
}
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
setState(() {
qrText = scanData.code;
});
});
}
Future<void> _saveQRCodeToFirestore(String qrText) async {
CollectionReference qrCodes =
FirebaseFirestore.instance.collection('qr_codes');
await qrCodes.add({
'content': qrText,
'timestamp': FieldValue.serverTimestamp(),
}).then((value) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('QRコードの内容がFirebaseに保存されました')));
}).catchError((error) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('保存に失敗しました: $error')));
});
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
}