问题描述
在使用本地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
上阅读更多内容 https://developer.android.com /guide/topics/manifest/application-element
换句话说,如果您的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功能模拟器时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!