androidデバイスにhttp通信をするスイッチを作ってみた

前回VScodeでFlutterを動かしてみました。今回はそちらを使って、androidデバイスから自分のPCにデータを送信しようと思います。

Node-REDの設定

まずはhttp通信のための設定をしていきます。
自分のPCでNode-REDを開き、下記のようにノードを追加してください。

httpの中身は、メソッドをPOSTにして自分のPCのIPアドレスを指定、後ろに何かを追加してください。(今回はtestにしました)

後ろに追加した名前を、http inノードに追加します。

最後に必ずhttp requestをhttp inに接続してください。返し値がないとrequestノードが処理を終了できず止まってしまいます。
これでhttpの設定は完了です。

VScodeの設定

VScodeで、Flutterの「main.dart」を開きます。こちらのファイルの場所は、それぞれ異なります。
前回作ったtest内にある「lib」フォルダーにあります。
ご自身の作ったフォルダーを探してください。(下図参照)

こちらの中身を下のコードに変更します。

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Rebuild only when necessary')),
        body: const Align(
          alignment: Alignment.topCenter,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [SizedBox(height: 16), ClickyBuilder()],
          ),
        ),
      ),
    );
  }
}

//StatefulWidget:ボタンの状態(ON/OFF)を管理するために使用
class ClickyBuilder extends StatefulWidget {
  const ClickyBuilder({super.key});

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

//ボタンの表示内容と、押せるかどうかの状態を管理
class ClickyBuilderState extends State<ClickyBuilder> {
  bool isSending = false; //ボタンが送信中かどうかを管理(送信中は無効化)
  late DateTime builtTime; //ボタン表示に使う時刻(再描画時に更新)

  // 初期化処理:ウィジェット(UIに使われるもの)が作られた直後に呼ばれる
  @override
  void initState() {
    super.initState();
    builtTime = DateTime.now();
  }

  //時間取得
  String pad(int i) => i.toString().padLeft(2, '0');

  // ボタン押下時に呼ばれる:送信状態に切り替え、HTTPリクエストを実行
  Future<void> sendRequest() async {
    setState(() {
      isSending = true;
    });

    //httpのURL先
    try {
      await http.post(Uri.parse('http://192.168.1.37:1880/test'), body: 'test');
    } catch (e) {
      debugPrint('送信エラー: $e');
    }
    //3秒間操作を受け付けない
    await Future.delayed(const Duration(seconds: 3));
    //button再度有効化
    setState(() {
      isSending = false;
      builtTime = DateTime.now(); // ボタン再有効化時に時刻を更新
    });
  }

  //buttonの色の変更
  //今のUIを取得
  @override
  Widget build(BuildContext context) {
    //背景切り替え
    return ElevatedButton(
      style: ElevatedButton.styleFrom(
        //状態を見てblueならgreyにgreyならblueに
        backgroundColor: isSending ? Colors.grey : Colors.blue,
      ),
      child: Text(
        isSending
            ? '送信' // isSending = true のときの表示
            : 'Built at ${builtTime.hour}:${pad(builtTime.minute)}:${pad(builtTime.second)}', //時間表記
      ),
      onPressed: isSending ? null : sendRequest, // 状態に応じてボタンの有効/無効を切り替え
    );
  }
}

コメントである程度書いています。よく読んでみてください。
コメントのない初めの部分は、ボタンのボックスを作っている部分になります。
こちらに置きかいたら、ビルドして書き込むのですが、まず簡単にVScodeで書き込んでみます。

書き込みの準備(android側)

書き込みをするにあたり、androidを開発者モードにしUSBでのファイル転送を許可する必要があります。
バージョンによって開発者モードの開き方が違うのですが、基本的に
設定→デバイス情報(タブレット情報)→OSバージョンを複数回タップ(何回かすると下に通知が来ます)
で開発者モードはオンになります。


オンになると、設定のどこかに開発者向けオプションが出てくるため、そちらを開き
USBデバックとUSB経由でインストールをオンにします。

こちらで設定完了です。

VScodeでの書き込み

VScodeでは、そのまま接続されているandroidに書き込むことができます。
ただし、VScodeが起動できる環境、コードの書いているファイルが必要など、条件が必要になります。
書き込みは簡単で、下のterminalからFlutterで作ったファイルを指定します。

ここで下記のコマンドを実行します。

すると繋がっているandroidに書き込みがされます。
終了するときは「q」で止まります。

APKでの書き込み

こちらは、VScodeの環境がなくてもファイルさえ持っていれば誰でも書き込むことができます。
まず、自分のPCのterminalを開きます。
そして、androidに送るファイルをVScode同様に指定します。

ここで下記コマンドを実行します。

flutter build apk

そうすると、上記のように「app-release.apk」ファイルのパスが出てきます。
これで転送用ファイルができました。
次に、こちらのパスの絶対パスを確認しに行きます。

こちらのパスをコピーしてメモします。
次に、繋がっているデバイスを確認します。
下記のコマンドを実行すると、繋がっているデバイスが見えるので、一番右のIDをコピーして、こちらもメモします。

adb devices -l

そうしましたら、最後に下記のコマンドに取ってきたIDとパスをあてはめます。

adb -s デバイスID install "絶対パス"

結果自分はこうなりました。

adb -s e5e6312a install "C:\Users\koshida\test\build\app\outputs\flutter-apk\app-release.apk"

これを実行します。

するとandroidデバイスに、インストール承認が出てきますのでこちらを承認します。

するとデバイスにインストールされます。

これでデバイスのtestを起動し、ボタンを押すとNode-REDにtestとデータが送られてきます。

httpが送られない場合

自分は、VScodeで起動した際、httpが送られたのにAPKにしたとたんhttpが送られない現象になりました。
こちらは、android側がhttps出ない場合にブロックしている可能性がありそうです。
そのため、httpが送られない場合下記の部分を変更してみてください。
test→android→app→src→main→AndroidManifest.xml
こちらをVScodeで開きます。

この中身を下記に変更してください。(なお元のコードはどこかにコピーして保存してください)

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:label="test"
        android:icon="@mipmap/ic_launcher"
        android:usesCleartextTraffic="true">

        <!-- Flutter V2 embedding の指定 -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:theme="@style/LaunchTheme"
            android:launchMode="singleTop"
            android:windowSoftInputMode="adjustResize"
            android:hardwareAccelerated="true"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode">
            
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>

        </activity>
    </application>
</manifest>

変更後保存して、PCのterminalからもう一度APKを生成します。

flutter build apk

そして、もう一度書き込んでみてください。

adb -s デバイスID install "絶対パス"

これでNode-REDにデータが送信されると思います。