🦋

FlutterからUnityにCSVDataを送る 1.Flutter側

2023/12/08に公開

これはリスクのある方法です

Flutterをfrontとして、backendはServerpodで、
userが協働して作るDatabaseを構築中。
Flutterでデータを登録、検索、検索結果の表示もする。
じゃ、Unityはなんなんだというと、Databaseを三次元空間として表示する。
その三次元空間内を動き回ることもできる。
つまり、大きな図書館内を歩き回るように、Databaseの中を歩き回る。
それでともかく、FlutterからUnityにDataを送りたい。
Flutterのアプリ上で、これ、Unityで見たいぞ、となったら、
ボタン一つでDataを抱えてUnityに飛びたい。

そんなことできるか、と爺様に聞くと、できる、という。
ただし、推奨しない、という。
データ量に制限があるし、セキュリティ面の問題もあるという。

推奨されないのに、あえてやる理由

今、どういう状況か。
表示画面としてのUnityはfirebaseHostingで公開されている。
一方、ServerpodのProjectとして制作中のFlutterアプリは、
まだuploadできていない。
Serverpodが「近日Upgrade!」というから、それを待っている。
uploadしたら、ServerpodにはWebServerがついているので、
Unityもそこにdeployできる。
serverを介して、Dataのやりとりができる。
が、現状ではそれができない。
ともかく、Dataを受け取って、表示できるか、その実験のために
推奨されない方法を、あえてとろうというわけ。

手順

  • 検索結果をListとして取得
  • ListをCSVにconvert
  • CSVをUriにencode
  • encodeしたDataを含むUrlをつかって、url_launcherで飛ぶ

紆余曲折

いきなりUnityがうまく開いて、おおおっ! ってなったが、
よく見たら関数がうまく書けてなくて、肝心の検索結果が空だった。
なので、ふつうのUrlでふつうに飛んだだけ、なのですぐに開いた。

関数を書き直したら、当然のように飛べなかった。
Urlが長すぎますって書いてある。
やっぱそうだよねえ、と、妙に納得。
でも、今回もよく見たら、これはこれで関数のミスで、
絞り込まれずに百件ものDataがencodeされている。
うーん、将来serverで繋がったら百件送ることもあるだろうけど、
今はそんなに要らん。

で、また関数を書き直して、うまく十件に絞り込んだら、
おおおおっ! ちゃんとUnityが開いたではないか!
拒否られなかったとはいえ、結構長いUrlだ。
まあ、十件、実験、ちょうどいい。
十件って、正しい日本語ではじゅっけん、じゃなく、じっけんって発音するって知ってました?
もちろん、これは実験なのだから、50件はいけるか、とか、25件はどうか、とか
やってみてもよいのだけれど、今日はここまでにする。

記事としてはムダなコードも入ってるけど

これ以上もの考える力が残っていないので、全部貼り付けました(゚゚)(。。)ペコッ。

import 'package:acorn_client/acorn_client.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import '../search/multiple_search_page.dart';

class FourDViewPage extends StatefulWidget {
  final List<int>? principalIds;

  const FourDViewPage({super.key, this.principalIds});

  
  _FourDViewPageState createState() => _FourDViewPageState();
}

class _FourDViewPageState extends State<FourDViewPage> {
  List<WithGlobe> withGlobes = [];

  
  void initState() {
    super.initState();
  }

  ///前ページでの検索結果をもとに、Unityに送るべきListを取得する。
  Future<void>fetchWithGlobe({List<int>? principalIds}) async {
    try {
      withGlobes = await client.withGlobe.getWithGlobe(keyNumbers: widget.principalIds);
      print('fetch with $principalIds');
    } catch (e) {
      debugPrint('$e');
    }
  }
  
  ///取得したListをCsvに変換する。
  String convertListGlobeToCsv(List<WithGlobe> withGlobes) {
    if (withGlobes.isEmpty) return '';

    List<String> rows = [];
    rows.add('annee, affair, location, precise, x_coordinate, y_coordinate, z_coordinate, coefficient');

    for (var withGlobe in withGlobes) {
      List<dynamic> row = [
        withGlobe.annee,
        withGlobe.affair,
        withGlobe.location,
        withGlobe.precise,
        withGlobe.x_coordinate,
        withGlobe.y_coordinate,
        withGlobe.z_coordinate,
        withGlobe.coefficient,
      ];
      rows.add(row.join(','));
    }
    return rows.join('\n');
  }
  
  ///変換したCSVDataをUriにencodeし、さらにurlとしてparseして飛ぶ。
  Future onLaunchUrl() async {
    String csvGlobe = convertListGlobeToCsv(withGlobes);
    print(withGlobes);
    String encodedCsvGlobe = Uri.encodeComponent(csvGlobe);
    print(encodedCsvGlobe);
    final Uri url = Uri.parse('https://tempo-spaco.web.app?data=$encodedCsvGlobe');
    if (await canLaunchUrl(url)) {
      await launchUrl(url);
    }
  }

  
  Widget build(BuildContext context) {
    return Center(
      child: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon:const Icon(Icons.arrow_back),
            onPressed: () {
              Navigator.push<String>(
                context,
                MaterialPageRoute(
                  builder: (context) => MultiSearchPage(),
                ),
              );
            },
          ),
          title: const Text('4D VIEW'),
        ),
        floatingActionButton: Padding(
          padding: const EdgeInsets.all(8.0),
          child: FloatingActionButton.extended(
              onPressed: () async {
                ///Listを取得する。
                await fetchWithGlobe(principalIds: widget.principalIds);
                ///飛ぶ。
                onLaunchUrl();
              },
              label: const Text ('Jump for Unity')),
        ),

        body: Container(
          constraints: const BoxConstraints.expand( ),
          decoration: const BoxDecoration(
            image: DecorationImage(
              image: AssetImage('assets/images/4d.png'),
              fit: BoxFit.cover,
            ),
          ),
        ),
      ),
    );
  }
}

flutter unity widgetがあるでしょう!?

知ってはいるけど・・・今回は却下。

Unityで遊んでみてください

https://tempo-spaco.web.app

Flutter大学

Discussion