从Flutter应用程序连接到本地Firebase功能模拟器时出错 [英] Error connecting to local Firebase functions emulator from Flutter app

查看:58
本文介绍了从Flutter应用程序连接到本地Firebase功能模拟器时出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用本地Firebase函数仿真器作为后端设置我的项目,并从Android仿真器调用Firebase onCall函数之后,我得到了这个非常没有信息的错误消息PlatformException(functionsError, Cloud function failed with exception., {code: INTERNAL, details: null, message: INTERNAL}).以下是完整的错误消息:

After setting up my project with a local Firebase functions emulator as my backend, and calling my Firebase onCall function from my Android emulator, I get this very non-informative error message PlatformException(functionsError, Cloud function failed with exception., {code: INTERNAL, details: null, message: INTERNAL}). Full error message below:

E/flutter (20862): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(functionsError, Cloud function failed with exception., {code: INTERNAL, details: null, message: INTERNAL})
E/flutter (21445): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:569:7)
E/flutter (21445): #1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156:18)
E/flutter (21445): <asynchronous suspension>
E/flutter (21445): #2      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:329:12)
E/flutter (21445): #3      MethodChannelCloudFunctions.callCloudFunction (package:cloud_functions_platform_interface/src/method_channel_cloud_functions.dart:43:15)
E/flutter (21445): #4      HttpsCallable.call (package:cloud_functions/src/https_callable.dart:33:12)
E/flutter (21445): #5      ApiService.loadUserLessonsByLessonIds (package:kim/services/api.dart:28:21)
E/flutter (21445): #6      MapScreen.build.<anonymous closure> (package:kim/screens/map.dart:170:34)
E/flutter (21445): #7      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:779:19)
E/flutter (21445): #8      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:862:36)
E/flutter (21445): #9      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter (21445): #10     TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:504:11)
E/flutter (21445): #11     BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:282:5)
E/flutter (21445): #12     BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:217:7)
E/flutter (21445): #13     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:475:9)
E/flutter (21445): #14     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:76:12)
E/flutter (21445): #15     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:122:9)
E/flutter (21445): #16     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:379:8)
E/flutter (21445): #17     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:120:18)
E/flutter (21445): #18     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:106:7)
E/flutter (21445): #19     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19)
E/flutter (21445): #20     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
E/flutter (21445): #21     GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
E/flutter (21445): #22     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
E/flutter (21445): #23     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
E/flutter (21445): #24     _rootRunUnary (dart:async/zone.dart:1196:13)
E/flutter (21445): #25     _CustomZone.runUnary (dart:async/zone.dart:1085:19)
E/flutter (21445): #26     _CustomZone.runUnaryGuarded (dart:async/zone.dart:987:7)
E/flutter (21445): #27     _invoke1 (dart:ui/hooks.dart:275:10)
E/flutter (21445): #28     _dispatchPointerDataPacket (dart:ui/hooks.dart:184:5)
E/flutter (21445): 

服务器代码index.ts:

import * as functions from 'firebase-functions'

interface LoadUserLessonsData {
  lessonIds: string[]
}

export const loadUserLessons = functions.https.onCall((data: LoadUserLessonsData, context) => {
  const uid = context.auth?.uid
  const ids = data.lessonIds
  console.log(uid, ids)
})

运行firebase emulators:start --only functions后的服务器控制台窗口:

The server console window after running firebase emulators:start --only functions:

...
+  functions[loadUserLessons]: http function initialized (http://localhost:5001/project-name/us-central1/loadUserLessons).
...
┌───────────┬────────────────┬─────────────────────────────────┐
│ Emulator  │ Host:Port      │ View in Emulator UI             │
├───────────┼────────────────┼─────────────────────────────────┤
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
└───────────┴────────────────┴─────────────────────────────────┘

客户端应用代码api.dart:

import 'dart:io';

import 'package:cloud_functions/cloud_functions.dart';
import 'package:myapp/services/config.dart';

class ApiService {
  static final ApiService _apiService = ApiService._internal();
  static final _functions = CloudFunctions.instance;

  ApiService._internal();

  factory ApiService() {
    init();
    return _apiService;
  }

  static void init() {
    // 10.0.2.2 is the special IP address to connect to the 'localhost' of the host computer from an Android emulator.
    final origin = Platform.isAndroid ? 'http://10.0.2.2:5001' : 'http://localhost:5001';
    _functions.useFunctionsEmulator(origin: origin);
  }

  static Future<dynamic> loadUserLessons(List<String> lessonIds) {
    final HttpsCallable callable = _functions.getHttpsCallable(
      functionName: 'loadUserLessons',
    );
    return callable.call({
      'lessonIds': lessonIds,
    });
  }
}

如何正确设置Flutter应用程序以连接到本地仿真器?

What can I do to correctly setup my Flutter app to connect to my local emulator?

请注意,无论仿真器是否在运行,错误消息都是相同的.仿真器也不会在控制台日志中注册任何事件.但是,当仿真器正在运行时,向功能端点发送自定义请求(例如,通过诸如"REST Api Client"之类的Android应用)确实会使仿真器做出反应.

It should be noted that the error message is the same regardless if the emulator is running or not. The emulator doesn't register any events in the console logs either. However, when the emulator is running, sending an custom request (e.g. through an Android app like "REST Api Client") to the function endpoint does make the emulator react.

这意味着问题仅出在Flutter代码中(我的或cloud_functions Flutter软件包).至少,这是我到目前为止的结论.

This means that the problem is solely in the Flutter code (mine or cloud_functions Flutter package). At least, that's my conclusion so far.

推荐答案

幸运的是,我已经设置了Crashlytics,该错误信息得到了更详细的信息,其中之一是:

Luckily I had set up Crashlytics that had been given more detailed error messages, one of which was:

CLEARTEXT communication to 10.0.2.2 not permitted by network security policy

这使我注意到了这个Stackoverflow问题以及Ashish John的评论:

which pointed me to this Stackoverflow question and the comment made by Ashish John:

OkHttp:<-HTTP失败:java. net.UnknownServiceException:网络安全策略不允许与10.0.2.2的CLEARTEXT通信

您可以"android:usesCleartextTraffic =" true".在清单文件的应用程序"标签中.如果您的API/链接不支持https& ;,则会发生此问题.您使用的是"Android P"或更高版本.

You can you 'android:usesCleartextTraffic="true"' in 'Application' tag in manifest file. This problem occurs if your API/Link doe not support https & you are using 'Android P' or above.

android:usesCleartextTraffic上阅读更多内容 https://developer.android.com /guide/topics/manifest/application-element

指示应用程序是否打算使用明文网络流量,例如明文HTTP. 目标API级别为27或更低的应用程序的默认值为"true".面向API级别28或更高级别的应用默认为"false" .

换句话说,如果您的Android模拟器运行的是Android API级别28或更高版本,则需要将android:usesCleartextTraffic="true"添加到应用程序AndroidManifest.xml

In other words, if your Android emulator is running Android API level 28 or higher you need to add android:usesCleartextTraffic="true" to the <application> tag in your app's AndroidManifest.xml

现在,我们需要允许Ahmed Ghrib解决的Android仿真器和Firebase功能仿真器之间的通信.

Now we need to permit the traffic between Android emulator and the Firebase functions emulator, which Ahmed Ghrib solved.

OkHttp:<-HTTP失败: java.net.UnknownServiceException:网络安全策略不允许与10.0.2.2的CLEARTEXT通信

使用以下代码创建文件network_security_config.xml并将其放置在[PROJECT]/android/app/src/main/res/xml中:

Create a file network_security_config.xml and place it in [PROJECT]/android/app/src/main/res/xml with the following code:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain>10.0.2.2</domain>
    </domain-config>
</network-security-config>

这是对艾哈迈德·格里布(Ahmed Ghrib)的回答的修改版本,以限制纯文本流量仅在Android模拟器和Firebase功能模拟器之间使用.

This is a modified version made to Ahmed Ghrib's answer, to limit clear text traffic to only be used between the Android emulator and the Firebase functions emulator.

这篇关于从Flutter应用程序连接到本地Firebase功能模拟器时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆