質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

641閲覧

FlutterからAPI(PHP)へ、リモートデータ通信ができない

Y.Mamoru

総合スコア47

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2022/10/03 10:41

編集2022/10/05 11:51

前提

Flutterアプリの画面で入力した内容を、
PHPで作成したAPIにリモートで飛ばすのですが
値を飛ばすことができません。

実現したいこと

Flutterの画面から入力した値をPHPで作成したAPIに送信する、ログイン機能を作成しようとしてます。

発生している問題・エラーメッセージ

Flutter側の送信でエラーが起こっているようです。

dart

1XMLHttpRequest error. 2No ScaffoldMessenger widget found. 3Login widgets require a ScaffoldMessenger widget ancestor. 4The specific widget that could not find a ScaffoldMessenger ancestor was: 5 Login 6The ancestors of this widget were: 7 [root] 8Typically, the ScaffoldMessenger widget is introduced by the MaterialApp at the top of your application widget tree.

該当のソースコード

dart

1//ログイン処理 2 Future<void> _login() async { 3 if (!_formKey.currentState!.validate()) { 4 return; 5 } 6 7 setState(() { 8 _isLoading = true; 9 }); 10 //dataに値が入っていることは確認できています 11 Map<String, String> data = {'email': _mail!, 'password': _password!}; 12 13 Response? res; 14 try { 15 //このPOST処理に入ったときにエラーが発生します。 16 res = await Network().postData(data, '/ReadUserInfo'); 17 } catch (e) { 18 // debugPrint(e.toString()); 19 print("エラー内容:"+e.toString()); 20 } 21 22 if (res == null) { 23 if (mounted) { 24 ScaffoldMessenger.of(context).showSnackBar( 25 const SnackBar(content: Text("エラーが発生しました。")), 26 ); 27 } 28 setState(() { 29 _isLoading = false; 30 }); 31 return; 32 } 33 34 var body = json.decode(res.body); 35 36 // エラーの場合 37 if (res.statusCode != 200) { 38 if (mounted) { 39 ScaffoldMessenger.of(context).showSnackBar( 40 SnackBar(content: Text(body['message'])), 41 ); 42 } 43 setState(() { 44 _isLoading = false; 45 }); 46 return; 47 } 48 49 // 正常終了の場合 50 SharedPreferences localStorage = await SharedPreferences.getInstance(); 51 localStorage.setString('token', json.encode(body['token'])); 52 localStorage.setString('user', json.encode(body['user'])); 53 54 if (!mounted) return; 55 Navigator.push( 56 context, 57 MaterialPageRoute(builder: (context) => const TabPage()), 58 ); 59 } 60 61//以下ログイン画面生成処理 62 63 Widget build(BuildContext context) { 64 return MaterialApp( 65 home:Scaffold( 66 appBar: AppBar( 67 centerTitle: true, 68 title: const Text("ログイン"), 69 ), 70 body: SafeArea( 71 child: _isLoading 72 ? const Center( 73 child: CircularProgressIndicator(), 74 ) 75 : Form( 76 key: _formKey, 77 child: Container( 78 padding: const EdgeInsets.all(16), 79 child: Column( 80 children: [ 81 TextFormField( 82 keyboardType: TextInputType.emailAddress, 83 decoration: const InputDecoration( 84 hintText: "メールアドレス", 85 ), 86 validator: (emailValue) { 87 if (emailValue == null || emailValue == "") { 88 return 'メールアドレスは必ず入力してください。'; 89 } 90 _mail = emailValue; 91 return null; 92 }, 93 ), 94 TextFormField( 95 keyboardType: TextInputType.visiblePassword, 96 obscureText: isHiddenPassword, 97 decoration: InputDecoration( 98 hintText: "パスワード", 99 suffixIcon: IconButton( 100 icon: Icon(isHiddenPassword 101 ? Icons.remove_red_eye 102 : Icons.visibility_off), 103 onPressed: () { 104 setState(() { 105 isHiddenPassword =!isHiddenPassword; 106 }); 107 }), 108 ), 109 110 validator: (passwordValue) { 111 if (passwordValue == null || 112 passwordValue == "") { 113 return 'パスワードは必ず入力してください。'; 114 } 115 _password = passwordValue; 116 return null; 117 }, 118 ), 119 const SizedBox( 120 height: 32, 121 ), 122 ElevatedButton( 123 onPressed: () { 124 _login(); 125 }, 126 child: const Text("ログイン")), 127 const SizedBox( 128 height: 16, 129 ), 130 ElevatedButton( 131 onPressed: () { 132 runApp(const SignUpPage() 133 ); 134 }, 135 child: const Text("会員登録")), 136 const SizedBox( 137 height: 16, 138 ), 139 ], 140 ), 141 ))))); 142 } 143

dart

1//APIへ接続するクラスです 2import 'dart:convert'; 3import 'package:shared_preferences/shared_preferences.dart'; 4import 'package:http/http.dart'; 5class Network { 6 // Androidシュミレーターを使う場合はlocalhostを10.0.2.2に変更する 7 //ここでPHP側のURLを指定(こちらのURLが正しいことは確認済みです。直接叩いて特定のファイルまで飛ぶことができます) 8 final String _url = 'https://XXX.XXX.XXX.XX/index.php'; 9 String? token; 10 11 // SharedPreferences(データを保存する仕組み)からトークンを取得 12 _setToken() async { 13 SharedPreferences localStorage = await SharedPreferences.getInstance(); 14 String? localToken = localStorage.getString('token'); 15 16 // なぜかlocalStorageから取得した値の前後に"が入るので仕方なくここで置換する 17 if (localToken != null) { 18 token = localToken.replaceAll('"', ''); 19 } 20 } 21 22 // ヘッダー情報をセット 23 _getHeaders() => { 24 'Content-type': 'application/json', 25 'Accept': 'application/json', 26 'Authorization': 'Bearer $token' 27 }; 28 29 // POST 30 //ここのapiUrlで、PHP側のログインAPIを指定(/login など) 31 Future<Response> postData(data, String apiUrl) async { 32 await _setToken(); 33 Uri fullUrl = Uri.parse(_url + apiUrl); 34//この時点でfullUrlとdataの中身が正しいことは確認済みです 35 return await post(fullUrl, body: jsonEncode(data), headers: _getHeaders()); 36 } 37 38 // GET 39 Future<Response> getData(String apiUrl) async { 40 await _setToken(); 41 Uri fullUrl = Uri.parse(_url + apiUrl); 42 Response res = await get(fullUrl, headers: _getHeaders()); 43 return res; 44 } 45} 46

試したこと

・作成するにあたって参考にしているサイトはこちらです。
https://qiita.com/atm_33/items/9ffc89caf1c2b6d6d661

・デバッグで確認したところ入力した内容は変数に格納されています。
(_mailと_passwordです)

・postDataメソッドを実行した後にエラーが発生します

・「XMLHttpRequest error.No ScaffoldMessenger widget found.」
をキーワードで検索した結果、同様の現象について書かれた記事があったので書かれている通りグローバルキーを作ってみましたが、結果は変わりませんでした。
https://stackoverflow.com/questions/66833689/flutter-no-scaffoldmessenger-widget-found

・デバッグで確認すると、API接続ファイルの方で作成しているlocal tokenがnullであることがわかりました。
これが原因かと思い、local tokenの作成方法を調べていますが、
すでに実装コードは書いているので、なぜnullなのかもわかっていない状態です。

追記です。
tokenがnullであることは、もしかしたら問題ないかもしれません。
定義の段階でtokenはnull許容であることと、
ここでのtokenはAPIから受け取る際に使われると参考サイトに書かれていたことから判断しました。

補足情報(FW/ツールのバージョンなど)

開発ツール:AndroidStudio4.01
DartSDKバージョン:2.17.6
Flutterバージョン:3.05

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Y.Mamoru

2022/10/03 10:54

前回はPHP側の受け取り方を教えていただき、ローカル上でそれはできたのですが 今回は別で作成されたAPIにリモートで接続させる流れになっています。 前回と同様にしてみたのですが、 できなかったので再度質問として挙げさせていただきました
m.ts10806

2022/10/03 10:57

そのリモート先は、例えばローカルからブラウザでURLそのまま実行してちゃんとアクセスは出来てるんでしょうか。 ポート開放など適切な設定はされていますか?
m.ts10806

2022/10/03 10:58 編集

えっと、タイトル紛らわしいのでリモート先であることはタイトルと本文にも明記しておいてもらえると。コードまで全部読まないと分からないのは説明不足で伝わらないと思いますので。
Y.Mamoru

2022/10/03 11:07

ブラウザからリモート先へのアクセスはできています。 ポートの開放もできている状態です。 すみません、タイトルと本文を修正します
guest

回答1

0

ベストアンサー

原因かはわからないのですが、MaterialAppを使い忘れていると出そうな感じがします。
わからないですが。
ちょっと考えにくいような気もしますが、そこら辺のコードは見ることができないので一応。

投稿2022/10/03 16:03

moriman

総合スコア615

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Y.Mamoru

2022/10/04 01:02

回答ありがとうございます。 MaterialAppは書いているんですよね、、、 一応本文に画面生成のコードも追記します。 ありがとうございます。
moriman

2022/10/04 06:46

``` void main(){ runApp(MaterialApp(home:Login(),)); } ``` のようにLoginウィジェットの(ウィジェットツリーの中での)上位にMaterialAppを配置する必要があると思います。 それでNo ScaffoldMessenger widget found.のエラーは出なくなると思います。 ScaffoldMessengerを保持しているのはMaterialAppで、 contextに対応するウィジェット(Login)がその親(あるいは祖先)ウィジェットの中からScaffoldMessengerを探すんですが、自分自身が持つMaterialAppは探す対象に含まれないので、上記のエラーが出ている、という感じです。
Y.Mamoru

2022/10/05 02:51

ありがとうございます! 記載の通り、runAppにMaterialAppを追記すると動きました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問