2

I've a deployed a callable function, say foo, using

firebase deploy --only functions:foo

and I'm calling it in Flutter using:

var result = await FirebaseFunctions.instance.httpsCallable('foo')();
var data = result.data;

All good. But I'd like to run this function in the Firebase Emulator. When I run

firebase emulators:start --only functions

I can see the emulator up and running, and I'm connecting my Flutter app to the emulator using:

FirebaseFunctions.instance.useFunctionsEmulator('localhost', 4000);

However, I don't know how to invoke the callable foo in Flutter using the Firebase Emulator. I saw this related thread but it doesn't really answer my question.


EDIT:

Here's the console output:

✔  functions[us-central1-foo]: http function initialized (http://localhost:5001/my_project/us-central1/foo).

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌───────────┬────────────────┬─────────────────────────────────┐
│ Emulator  │ Host:Port      │ View in Emulator UI             │
├───────────┼────────────────┼─────────────────────────────────┤
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
├───────────┼────────────────┼─────────────────────────────────┤
│ Firestore │ localhost:8080 │ http://localhost:4000/firestore │
└───────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

I tried

useFunctionsEmulator('localhost', 4000);
useFunctionsEmulator('localhost', 5001);

but both of them throw the following error on calling httpsCallable('foo') but without the emulators, this function does work.

[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: [firebase_functions/unavailable] UNAVAILABLE

iDecode
  • 22,623
  • 19
  • 99
  • 186
  • Have you already checked here: https://firebase.flutter.dev/docs/functions/usage#emulator-usage? – Mattia Galati Aug 08 '21 at 13:04
  • @MattiaGalati Yes, I checked that out already but there was no helpful code in the link. – iDecode Aug 08 '21 at 15:05
  • If you run the `FirebaseFunctions.instance.httpsCallable('foo')` after the `FirebaseFunctions.instance.useFunctionsEmulator` setting, won't the function on the emulator being called? Does you emulator function replies if you call it, for example, with Postman or similar tool? – Mattia Galati Aug 08 '21 at 20:33
  • @MattiaGalati Please check out the edited post. – iDecode Aug 09 '21 at 05:52
  • As per you edit, I see the cloud function should be available on localhost:5001. Does calling it from a PostMan-like tool (or curl) on the same pc results in a correct reply? If so, and you are testing the app on a phisical device, maybe the Dart code should be modified to use the IP of the pc where the emulator is running in the local network. – Mattia Galati Aug 09 '21 at 09:51
  • @MattiaGalati I don't have the PostMan installed on my computer. I'm testing it on a physical device though. Can you please tell me how can I use the IP of the pc in this case? Thanks – iDecode Aug 10 '21 at 05:38
  • this code might run but depends on what platform you are: `curl --request [GET/POST] 'http://localhost:5001/[project]/[region if used]/[function]' --header 'Content-Type: application/json' --data-raw '{"data": {"foo": "bar"}}'` If the request reaches the local function, the run a `ipconfig` or `ifconfig` and search for your local lan IP, and on your dart code use `useFunctionsEmulator('[LOCAL_IP]', 5001);` – Mattia Galati Aug 11 '21 at 06:36

4 Answers4

1

I suspect your host and port values might be incorrect. When you start up your emulator, the logs will display all the ports that are being used for your various emulators. There's also the firebase.json file that has the port configurations for the emulators.

Also, localhost is not automatically identified by the clients. For Android you might have to configure networkSecurityConfig in your manifest by creating a network security config xml. For iOS, I think there should be something that needs to be added in the plist file - has to be checked confirmed.

Once your clients are able to access localhost (implicitly or explicitly), you can connect to your emulated functions. For example, I have explicitly state the host value in my code (this is not expected to change across restarts).

Here is the code that I use in Kotlin:

functions = FirebaseFunctions.getInstance()
    /*
    * Emulator
    * */
    if (emulatorMode) { //Local Testing
        functions.useEmulator("10.0.2.2", 5001)
    } else { //Live
        functions = Firebase.functions
    }

    // Call the function and extract the operation from the result
    return functions
        .getHttpsCallable(function)
        .call(inputData)
        .continueWith { task ->...
srinij
  • 471
  • 6
  • 10
  • Are you using a physical device or a device emulator? I think a physical device cannot connect to localhost on your computer and only device emulators can. `localhost:5001` is the right one to use in your code to connect to functions. – srinij Aug 10 '21 at 01:20
  • I'm using a physical device. Can I never be able to test the app on my device in that case? – iDecode Aug 10 '21 at 05:37
  • You should be able to by configuring the IP address of your machine as the host. I found this [https://stackoverflow.com/questions/66161387/firebase-firestore-emulator-on-physical-ios-android-device]. – srinij Aug 11 '21 at 00:26
  • Thanks, although I'm unable to find the answer but I'll surely give you an upvote for all your help later :) – iDecode Aug 11 '21 at 05:34
  • I updated my `firebase.json` file to use `"host": "0.0.0.0"` for functions emulator, did a fresh restart, and used `useFunctionsEmulator('my_ip_address', 5001);` but I'm still getting the same error I mentioned in my edited post. – iDecode Aug 11 '21 at 06:25
0

It doesn't seem like a port or setup issue to me. Your console seems to show the expected output.

Try this:

Inside Flutter, where you want to call the function, add:


http.get(Uri.parse('http://localhost:5001/my_project/us-central1/foo'))

You're going to have to set an env variable, that asks your application to check what environment it is in. If dev, then it should use url above, if prod it can use the prod url

jgrewal
  • 189
  • 1
  • 2
  • 11
  • Unhandled Exception: SocketException: OS Error: Connection refused, errno = 111, address = localhost, port = 45398. Can you post a full solution? – iDecode Aug 11 '21 at 06:19
0
this._cloudFunctions = FirebaseFunctions.instance;
_cloudFunctions.useFunctionsEmulator(origin: "http://<System's IP>:5001");

Systems ip we can get by typing ipconfig in command prompt. Make sure you connect your ip and run emulators start.

iDecode
  • 22,623
  • 19
  • 99
  • 186
Varun
  • 1,658
  • 1
  • 7
  • 11
0

For Flutter

As per the Firebase Flutter Docs- There is a useFunctionsEmulator module as part of your Firebase Functions instance.

You can initialize it as follows:

FirebaseFunctions.instance.useFunctionsEmulator('localhost', 5001);

For Web

If you cd into the functions directory you can run npm start which will, by default, build and run the emulators locally in the shell. I've found this to be the only solution for testing callable functions locally.

The firebase team has provided a connectFunctionsEmulator submodule in the V9 modular SDK which is designed specifically to interact with your app locally.

You can checkout the official docs for this Here.

Running npm run serve will serve the emulator that you are expecting but I have been running into issues testing callable functions via url.

Rafael Zasas
  • 891
  • 8
  • 27
  • *Sidenote* Don't be afraid to use the V9 SDK as you can still use the `compat` library that they provide to upgrade specific solutions one at a time. – Rafael Zasas Nov 01 '21 at 22:28
  • Thanks but I wanted to test that on a real device. – iDecode Nov 04 '21 at 08:52
  • @iDecode I see. You can still run the shell emulator however and run the functions locally which will at least allow you to test them outside of the app environment. As for testing on the device it may be useful to convert the function to http on request. I added the Firebase docs instructions for Flutter in case anyone strolls by looking for more info. – Rafael Zasas Nov 05 '21 at 00:19
  • In case you missed it, I am already using `useFunctionsEmulator` and that too isn't working which is why the question was asked. – iDecode Nov 06 '21 at 07:58