2

I follow this course: https://firebase.google.com/docs/functions/callable#java_2 and i can't call my function. However i can call triggered functions:

In index.json

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

//firebase.functions().useFunctionsEmulator('http://localhost:5000') I don't know if i need to use that
//and don't find the path of the firebase module

exports.addMessage = functions.https.onCall((data, context) => {
    console.log("addMessage call");
    const text = data.text;
    const uid = context.auth.uid;
    const name = context.auth.token || null;
    const picture = context.auth.token.picture || null;
    const email = context.auth.token.email || null;
    
    // Checking attribute.
    if (!(typeof text === 'string') || text.length === 0) {
    // Throwing an HttpsError so that the client gets the error details.
    throw new functions.https.HttpsError('invalid-argument', 'The function must be called with ' +
        'one arguments "text" containing the message text to add.');
    }
    // Checking that the user is authenticated.
    if (!context.auth) {
    // Throwing an HttpsError so that the client gets the error details.
    throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
        'while authenticated.');
    }

    // Saving the new message to the Realtime Database.
    const sanitizedMessage = sanitizer.sanitizeText(text); // Sanitize the message.
    return admin.database().ref('/messages').push({
    text: sanitizedMessage,
    author: { uid, name, picture, email },
    }).then(() => {
    console.log('New Message written');
    // Returning the sanitized message to the client.
    return { text: sanitizedMessage };
    })
});

In Android Studio (java) :

public class MainActivity extends AppCompatActivity {
    private final static String TAG = "DebugTest";

    private DatabaseReference mRef ;
    private FirebaseFunctions mFunctions;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button clickBtn = findViewById(R.id.clickBtn);

        // WARNING: firebase emulators
        mRef = FirebaseDatabase
                .getInstance("http://10.0.2.2:9000?ns=my-firebase-application-xxxxx")
                .getReference();

        mFunctions = FirebaseFunctions.getInstance("http://10.0.2.2:9000?ns=my-firebase-application-xxxx");





        clickBtn.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        addMessage("salut les copains")
                        .addOnCompleteListener(new OnCompleteListener<String>() {
                            @Override
                            public void onComplete(@NonNull Task<String> task) {
                                Log.d(TAG,"onComplete call");
                                if (!task.isSuccessful()) {
                                    Exception e = task.getException();
                                    if (e instanceof FirebaseFunctionsException) {
                                        FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
                                        FirebaseFunctionsException.Code code = ffe.getCode();
                                        Object details = ffe.getDetails();
                                        Log.d(TAG,"problème dans appelle de la fonction addMessage: \n " + code.toString());
                                    }
                                    // ...
                                }

                                // ...
                            }
                        });

                    }
        });
    }

    private Task<String> addMessage(String text) {
        // Create the arguments to the callable function.
        Map<String, Object> data = new HashMap<>();
        data.put("text", text);
        data.put("push", true);

        return mFunctions
                .getHttpsCallable("addMessage")
                .call(data)
                .continueWith(new Continuation<HttpsCallableResult, String>() {
                    @Override
                    public String then(@NonNull Task<HttpsCallableResult> task) throws Exception {
                        // This continuation runs on either success or failure, but if the task
                        // has failed then getResult() will throw an Exception which will be
                        // propagated down.
                        String result = (String) task.getResult().getData();
                        Log.d(TAG, "result going to be send");
                        return result;
                    }
                });
    }
}

I have this in my Android console:

D/DebugTest: onComplete call
D/DebugTest: problème dans appelle de la fonction addMessage: 
     INTERNAL

So then (in ContinueWith) don't work or is not call.

And I don't have any log like "addMessage call" in firebase emulator...

Someone have any Idea.

PS: I don't know how to find the module to call firebase.functions().useFunctionsEmulator('http://localhost:5000')

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
AymericNgy
  • 43
  • 1
  • 7
  • I came across [this post](https://stackoverflow.com/questions/57684682/firebase-functions-emulator-usefunctionsemulator-method-not-working) and [this documentation](https://firebase.google.com/docs/functions/local-emulator) regarding firebase function emulator which you might find helpful, as it explains how to call firebase.functions().useFunctionsEmulator('http://localhost:5000'). – Artemis Georgakopoulou Jul 23 '20 at 11:17
  • Thanks, however do you know what is the path inside of the require. firebase = require('what is the name') ??? Please – AymericNgy Jul 23 '20 at 12:48
  • Do you mean to import Firebase cloud Functions as following const functions = require('firebase-functions'); ? – Nibrass H Jul 28 '20 at 14:54

4 Answers4

2

Be aware that when you use a mobile device in development you will need to instruct firebase to start with the device's local ip. See https://github.com/firebase/firebase-tools/issues/1943#issuecomment-581754837 However, when you use your computer's simulator, it should not return an internal error. I think they should have added a bit more data to the returned error.

Ben
  • 2,957
  • 2
  • 27
  • 55
0

Did someone manage to figure out what the problem was here? I am using Kotlin in Android:

functions = FirebaseFunctions.getInstance()
functions.useEmulator("10.0.2.2", 5001)

and am also getting an INTERNAL error.

0

I had a similar problem when calling functions in the emulator using my Flutter app.

I have multiple Firebase projects for each of my environments and therefore when I initialize Firebase in the app I provide FirebaseOptions depending on the environment. Within the FirebaseOptions is a projectId parameter which matches the project name in the Firebase console.

I found that when the call was made to the function in the emulator, it was not using the name of the project from the projectId parameter as I had expected but rather used the name of the FirebaseApp that is used when Firebase is initialized in the Flutter app. Since I wasn't providing a name, it was trying to make a call to a project called [Default] which didn't exist. When I initialized the app to have the same name as the projectId the internal error went away.

    Firebase.initializeApp({
        name: 'name_of_my_project',
        options: FirebaseOptions(),
    });

Also note that after naming the app, calling instance on any Firebase service needed to be updated to instanceFor since instance will always try to get an app named [Default]. Example:

    final auth = FirebaseAuth.instanceFor(app: Firebase.apps.first);
0

@Ben's answer led me to figure out why I was getting this error when testing a ReactNative app on a real iPad after using the iOS simulator fine. When calling the first Function I received this vague error.

I found that starting the emulator with the older style command: firebase serve --only functions -o 0.0.0.0 worked, but the newer firebase emulators:start --only functions did not.

This is because the -o parameter is instructing the emulator to host on all available network interfaces which in my case includes localhost, 127.0.0.1 and 192.168.1.107. The app on my iPad needs to be configured to connect to the emulator on the external LAN IP 192.168.1.107 (because localhost or 127.0.0.1 would be its own internal address).

The "firebase emulators" command doesn't have the -o option, so when you start it, the emulators host only on "localhost" by default, so the LAN IP is not bound to the server.

The solution (apart from using the older "serve" command) is to configure the firebase.json file:

"emulators": {
    "functions" : {
    "host": "0.0.0.0"
  }
}

Also note they changed the default port from 5000 ("firebase serve") to 5001 ("firebase emulators"), so make sure your client is configured right e.g. for me in ReactNative I have this in my boot:

if(__DEV__){
  console.warn('NOTICE: Firebase is using local EMULATORS in __DEV__ environment')
  connectFunctionsEmulator(fbFunctions , '192.168.1.107', 5001)`
}
scipilot
  • 6,681
  • 1
  • 46
  • 65