Firebase Summit에서 발표된 모든 내용을 살펴보고 Firebase로 앱을 빠르게 개발하고 안심하고 앱을 실행하는 방법을 알아보세요. 자세히 알아보기

앱에서 함수 호출

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

Firebase용 Cloud Functions 클라이언트 SDK를 사용하면 Firebase 앱에서 직접 함수를 호출할 수 있습니다. 이런 방식으로 앱에서 함수를 호출하려면 Cloud Functions에서 HTTPS 호출 가능 함수를 작성 및 배포한 다음 클라이언트 로직을 추가하여 앱에서 함수를 호출하세요.

HTTPS 호출 가능 함수는 HTTP 함수와 비슷하지만 동일하지는 않다는 점을 기억하는 것이 중요합니다. HTTPS 호출 가능 함수를 사용하려면 functions.https 백엔드 API와 함께 플랫폼용 클라이언트 SDK를 사용해야 합니다(또는 프로토콜 구현). 호출 가능 항목에는 HTTP 함수와 다음과 같은 주요 차이점이 있습니다.

  • 콜러블을 사용하면 Firebase 인증 토큰, FCM 토큰, 앱 체크 토큰(사용 가능한 경우)이 자동으로 요청에 포함됩니다.
  • functions.https.onCall 트리거는 요청 본문을 자동으로 역직렬화하고 인증 토큰의 유효성을 검사합니다.

Cloud Functions용 ​​Firebase SDK v0.9.1 이상은 다음 Firebase 클라이언트 SDK 최소 버전과 상호 운용되어 HTTPS 호출 가능 기능을 지원합니다.

  • Apple 플랫폼용 Firebase SDK 10.2.0
  • Android용 Firebase SDK 20.2.1
  • Firebase 자바스크립트 SDK 8.10.1
  • Firebase 모듈식 웹 SDK v. 9.0

지원되지 않는 플랫폼에서 빌드된 앱에 유사한 기능을 추가하려면 https.onCall 에 대한 프로토콜 사양을 참조하십시오. 이 가이드의 나머지 부분에서는 Apple 플랫폼, Android, 웹, C++ 및 Unity용 HTTPS 호출 가능 함수를 작성, 배포 및 호출하는 방법에 대한 지침을 제공합니다.

호출 가능 함수 작성 및 배포

functions.https.onCall 을 사용하여 HTTPS 호출 가능 함수를 생성합니다. 이 메서드는 data 와 선택적 context 라는 두 개의 매개변수를 사용합니다.

// Saves a message to the Firebase Realtime Database but sanitizes the text by removing swearwords.
exports.addMessage = functions.https.onCall((data, context) => {
  // ...
});

예를 들어 텍스트 메시지를 실시간 데이터베이스에 저장하는 호출 가능 함수의 경우 data 에는 메시지 텍스트가 포함될 수 있으며 context 매개변수는 사용자 인증 정보를 나타냅니다.

// Message text passed from the client.
const text = data.text;
// Authentication / user information is automatically added to the request.
const uid = context.auth.uid;
const name = context.auth.token.name || null;
const picture = context.auth.token.picture || null;
const email = context.auth.token.email || null;

호출 가능한 함수의 위치와 호출 클라이언트의 위치 사이의 거리로 인해 네트워크 대기 시간이 발생할 수 있습니다. 성능을 최적화하려면 해당하는 경우 함수 위치 를 지정하는 것을 고려하고 클라이언트 측 에서 SDK를 초기화 할 때 콜러블의 위치를 ​​설정한 위치와 정렬해야 합니다.

선택적으로 청구 사기 또는 피싱과 같은 남용으로부터 백엔드 리소스를 보호하는 데 도움이 되는 앱 체크 증명을 첨부할 수 있습니다. Cloud Functions에 대한 앱 체크 적용 활성화를 참조하십시오.

결과 다시 보내기

데이터를 다시 클라이언트로 보내려면 JSON 인코딩이 가능한 데이터를 반환하십시오. 예를 들어 더하기 연산의 결과를 반환하려면 다음과 같이 하십시오.

// returning result.
return {
  firstNumber: firstNumber,
  secondNumber: secondNumber,
  operator: '+',
  operationResult: firstNumber + secondNumber,
};

비동기 작업 후 데이터를 반환하려면 약속을 반환합니다. 약속에 의해 반환된 데이터는 클라이언트로 다시 전송됩니다. 예를 들어 호출 가능 함수가 실시간 데이터베이스에 작성한 삭제된 텍스트를 반환할 수 있습니다.

// 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 };
})

오류 처리

클라이언트가 유용한 오류 세부 정보를 얻도록 하려면 functions.https.HttpsError 의 인스턴스를 던져(또는 Promise가 거부된 것을 반환하여) 호출 가능 항목에서 오류를 반환합니다. 오류에는 functions.https.HttpsError 에 나열된 값 중 하나일 수 있는 code 특성이 있습니다. 오류에는 message 문자열이 있으며 기본값은 빈 문자열입니다. 또한 임의의 값이 있는 선택적 details 필드를 가질 수 있습니다. 함수에서 HttpsError 이외의 오류가 발생하면 클라이언트는 대신 INTERNAL 메시지 및 internal 코드와 함께 오류를 수신합니다.

예를 들어 함수는 호출 클라이언트에 반환할 오류 메시지와 함께 데이터 유효성 검사 및 인증 오류를 발생시킬 수 있습니다.

// 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.');
}

호출 가능 함수 배포

완성된 호출 가능 함수를 index.js 내에 저장하면 firebase deploy 를 실행할 때 다른 모든 함수와 함께 배포됩니다. 콜러블만 배포하려면 표시된 대로 --only 인수를 사용하여 부분 배포 를 수행합니다.

firebase deploy --only functions:addMessage

함수를 배포할 때 권한 오류가 발생하면 배포 명령을 실행하는 사용자에게 적절한 IAM 역할 이 할당되었는지 확인하십시오.

클라이언트 개발 환경 설정

전제 조건을 충족하는지 확인한 다음 앱에 필수 종속성 및 클라이언트 라이브러리를 추가합니다.

iOS+

안내에 따라 Firebase를 Apple 앱에 추가합니다 .

Swift Package Manager를 사용하여 Firebase 종속 항목을 설치하고 관리합니다.

  1. Xcode에서 앱 프로젝트를 연 상태에서 File > Add Packages 로 이동합니다.
  2. 메시지가 표시되면 Firebase Apple 플랫폼 SDK 저장소를 추가합니다.
  3.   https://github.com/firebase/firebase-ios-sdk
  4. Cloud Functions 라이브러리를 선택합니다.
  5. 완료되면 Xcode는 자동으로 백그라운드에서 종속성을 해결하고 다운로드하기 시작합니다.

Web version 9

  1. 지침에 따라 웹 앱에 Firebase를 추가합니다 . 터미널에서 다음 명령을 실행해야 합니다.
    npm install firebase@9.14.0 --save
    
  2. Firebase Core와 Cloud Functions를 모두 수동으로 요구합니다.

     import { initializeApp } from 'firebase/app';
     import { getFunctions } from 'firebase/functions';
    
     const app = initializeApp({
         projectId: '### CLOUD FUNCTIONS PROJECT ID ###',
         apiKey: '### FIREBASE API KEY ###',
         authDomain: '### FIREBASE AUTH DOMAIN ###',
       });
     const functions = getFunctions(app);
    

Web version 8

  1. 지침에 따라 웹 앱에 Firebase를 추가합니다 .
  2. Firebase 핵심 및 Cloud Functions 클라이언트 라이브러리를 앱에 추가합니다.
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-functions.js"></script>
    

Cloud Functions SDK는 npm 패키지로도 제공됩니다.

  1. 터미널에서 다음 명령을 실행합니다.
    npm install firebase@8.10.1 --save
    
  2. Firebase 코어와 Cloud Functions 모두 수동으로 필요:
    const firebase = require("firebase");
    // Required for side-effects
    require("firebase/functions");
    

Java

  1. 지침에 따라 Android 앱에 Firebase를 추가합니다 .

  2. 모듈(앱 수준) Gradle 파일 (일반적으로 <project>/<app-module>/build.gradle )에서 Cloud Functions Android 라이브러리에 대한 종속성을 추가합니다. Firebase Android BoM 을 사용하여 라이브러리 버전 관리를 제어하는 ​​것이 좋습니다.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:31.1.0')
    
        // Add the dependency for the Cloud Functions library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-functions'
    }
    

    Firebase Android BoM 을 사용하면 앱에서 항상 호환되는 버전의 Firebase Android 라이브러리를 사용합니다.

    (대안) BoM을 사용 하지 않고 Firebase 라이브러리 종속성 추가

    Firebase BoM을 사용하지 않기로 선택한 경우 종속성 줄에 각 Firebase 라이브러리 버전을 지정해야 합니다.

    앱에서 여러 Firebase 라이브러리를 사용하는 경우 BoM을 사용하여 모든 버전이 호환되도록 라이브러리 버전을 관리하는 것이 좋습니다.

    dependencies {
        // Add the dependency for the Cloud Functions library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-functions:20.2.1'
    }
    

Kotlin+KTX

  1. 지침에 따라 Android 앱에 Firebase를 추가합니다 .

  2. 모듈(앱 수준) Gradle 파일 (일반적으로 <project>/<app-module>/build.gradle )에서 Cloud Functions Android 라이브러리에 대한 종속성을 추가합니다. Firebase Android BoM 을 사용하여 라이브러리 버전 관리를 제어하는 ​​것이 좋습니다.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:31.1.0')
    
        // Add the dependency for the Cloud Functions library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-functions-ktx'
    }
    

    Firebase Android BoM 을 사용하면 앱에서 항상 호환되는 버전의 Firebase Android 라이브러리를 사용합니다.

    (대안) BoM을 사용 하지 않고 Firebase 라이브러리 종속성 추가

    Firebase BoM을 사용하지 않기로 선택한 경우 종속성 줄에 각 Firebase 라이브러리 버전을 지정해야 합니다.

    앱에서 여러 Firebase 라이브러리를 사용하는 경우 BoM을 사용하여 모든 버전이 호환되도록 라이브러리 버전을 관리하는 것이 좋습니다.

    dependencies {
        // Add the dependency for the Cloud Functions library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-functions-ktx:20.2.1'
    }
    

Dart

  1. 지침에 따라 Flutter 앱에 Firebase를 추가합니다 .

  2. Flutter 프로젝트의 루트에서 다음 명령을 실행하여 플러그인을 설치합니다.

    flutter pub add cloud_functions
    
  3. 완료되면 Flutter 애플리케이션을 다시 빌드합니다.

    flutter run
    
  4. 일단 설치되면 Dart 코드로 가져와서 cloud_functions 플러그인에 액세스할 수 있습니다.

    import 'package:cloud_functions/cloud_functions.dart';
    

C++

Android가 있는 C++의 경우:

  1. 안내에 따라 Firebase를 C++ 프로젝트에 추가합니다 .
  2. CMakeLists.txt 파일에 firebase_functions 라이브러리를 추가합니다.

Apple 플랫폼이 있는 C++의 경우:

  1. 안내에 따라 Firebase를 C++ 프로젝트에 추가합니다 .
  2. Podfile 에 Cloud Functions 팟(Pod)을 추가하십시오.
    pod 'Firebase/Functions'
  3. 파일을 저장한 다음
    pod install
    을 실행합니다.
  4. Firebase C++ SDK 의 Firebase 코어 및 Cloud Functions 프레임워크를 Xcode 프로젝트에 추가합니다.
    • firebase.framework
    • firebase_functions.framework

단일성

  1. 지침에 따라 Unity 프로젝트에 Firebase를 추가합니다 .
  2. Firebase Unity SDKFirebaseFunctions.unitypackage 를 Unity 프로젝트에 추가합니다.

클라이언트 SDK 초기화

Cloud Functions의 인스턴스를 초기화합니다.

빠른

lazy var functions = Functions.functions()

목표-C

@property(strong, nonatomic) FIRFunctions *functions;
// ...
self.functions = [FIRFunctions functions];

Web version 8

firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FUNCTIONS PROJECT ID ###'
  databaseURL: 'https://### YOUR DATABASE NAME ###.firebaseio.com',
});

// Initialize Cloud Functions through Firebase
var functions = firebase.functions();

Web version 9

const app = initializeApp({
  projectId: '### CLOUD FUNCTIONS PROJECT ID ###',
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
});
const functions = getFunctions(app);

Java

private FirebaseFunctions mFunctions;
// ...
mFunctions = FirebaseFunctions.getInstance();

Kotlin+KTX

private lateinit var functions: FirebaseFunctions
// ...
functions = Firebase.functions

Dart

final functions = FirebaseFunctions.instance;

C++

firebase::functions::Functions* functions;
// ...
functions = firebase::functions::Functions::GetInstance(app);

단일성

functions = Firebase.Functions.DefaultInstance;

함수 호출

빠른

functions.httpsCallable("addMessage").call(["text": inputField.text]) { result, error in
  if let error = error as NSError? {
    if error.domain == FunctionsErrorDomain {
      let code = FunctionsErrorCode(rawValue: error.code)
      let message = error.localizedDescription
      let details = error.userInfo[FunctionsErrorDetailsKey]
    }
    // ...
  }
  if let data = result?.data as? [String: Any], let text = data["text"] as? String {
    self.resultField.text = text
  }
}

목표-C

[[_functions HTTPSCallableWithName:@"addMessage"] callWithObject:@{@"text": _inputField.text}
                                                      completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
  if (error) {
    if ([error.domain isEqual:@"com.firebase.functions"]) {
      FIRFunctionsErrorCode code = error.code;
      NSString *message = error.localizedDescription;
      NSObject *details = error.userInfo[@"details"];
    }
    // ...
  }
  self->_resultField.text = result.data[@"text"];
}];

Web version 8

var addMessage = firebase.functions().httpsCallable('addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    var sanitizedMessage = result.data.text;
  });

Web version 9

import { getFunctions, httpsCallable } from "firebase/functions";

const functions = getFunctions();
const addMessage = httpsCallable(functions, 'addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    const data = result.data;
    const sanitizedMessage = data.text;
  });

Java

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();
                    return result;
                }
            });
}

Kotlin+KTX

private fun addMessage(text: String): Task<String> {
    // Create the arguments to the callable function.
    val data = hashMapOf(
        "text" to text,
        "push" to true
    )

    return functions
        .getHttpsCallable("addMessage")
        .call(data)
        .continueWith { task ->
            // This continuation runs on either success or failure, but if the task
            // has failed then result will throw an Exception which will be
            // propagated down.
            val result = task.result?.data as String
            result
        }
}

Dart

final result =
    await FirebaseFunctions.instance.httpsCallable('addMessage').call();

C++

firebase::Future<firebase::functions::HttpsCallableResult> AddMessage(
    const std::string& text) {
  // Create the arguments to the callable function.
  firebase::Variant data = firebase::Variant::EmptyMap();
  data.map()["text"] = firebase::Variant(text);
  data.map()["push"] = true;

  // Call the function and add a callback for the result.
  firebase::functions::HttpsCallableReference doSomething =
      functions->GetHttpsCallable("addMessage");
  return doSomething.Call(data);
}

단일성

private Task<string> addMessage(string text) {
  // Create the arguments to the callable function.
  var data = new Dictionary<string, object>();
  data["text"] = text;
  data["push"] = true;

  // Call the function and extract the operation from the result.
  var function = functions.GetHttpsCallable("addMessage");
  return function.CallAsync(data).ContinueWith((task) => {
    return (string) task.Result.Data;
  });
}

클라이언트에서 오류 처리

서버에서 오류가 발생했거나 결과 약속이 거부된 경우 클라이언트는 오류를 수신합니다.

함수에서 반환된 오류가 function.https.HttpsError 유형인 경우 클라이언트는 서버 오류에서 오류 code , messagedetails 를 받습니다. 그렇지 않으면 오류에 INTERNAL 메시지와 INTERNAL 코드가 포함됩니다. 호출 가능 함수의 오류를 처리 하는 방법에 대한 지침을 참조하세요.

빠른

if let error = error as NSError? {
  if error.domain == FunctionsErrorDomain {
    let code = FunctionsErrorCode(rawValue: error.code)
    let message = error.localizedDescription
    let details = error.userInfo[FunctionsErrorDetailsKey]
  }
  // ...
}

목표-C

if (error) {
  if ([error.domain isEqual:@"com.firebase.functions"]) {
    FIRFunctionsErrorCode code = error.code;
    NSString *message = error.localizedDescription;
    NSObject *details = error.userInfo[@"details"];
  }
  // ...
}

Web version 8

var addMessage = firebase.functions().httpsCallable('addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    var sanitizedMessage = result.data.text;
  })
  .catch((error) => {
    // Getting the Error details.
    var code = error.code;
    var message = error.message;
    var details = error.details;
    // ...
  });

Web version 9

import { getFunctions, httpsCallable } from "firebase/functions";

const functions = getFunctions();
const addMessage = httpsCallable(functions, 'addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    const data = result.data;
    const sanitizedMessage = data.text;
  })
  .catch((error) => {
    // Getting the Error details.
    const code = error.code;
    const message = error.message;
    const details = error.details;
    // ...
  });

Java

addMessage(inputMessage)
        .addOnCompleteListener(new OnCompleteListener<String>() {
            @Override
            public void onComplete(@NonNull Task<String> task) {
                if (!task.isSuccessful()) {
                    Exception e = task.getException();
                    if (e instanceof FirebaseFunctionsException) {
                        FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
                        FirebaseFunctionsException.Code code = ffe.getCode();
                        Object details = ffe.getDetails();
                    }
                }
            }
        });

Kotlin+KTX

addMessage(inputMessage)
    .addOnCompleteListener { task ->
        if (!task.isSuccessful) {
            val e = task.exception
            if (e is FirebaseFunctionsException) {
                val code = e.code
                val details = e.details
            }
        }
    }

Dart

try {
  final result =
      await FirebaseFunctions.instance.httpsCallable('addMessage').call();
} on FirebaseFunctionsException catch (error) {
  print(error.code);
  print(error.details);
  print(error.message);
}

C++

void OnAddMessageCallback(
    const firebase::Future<firebase::functions::HttpsCallableResult>& future) {
  if (future.error() != firebase::functions::kErrorNone) {
    // Function error code, will be kErrorInternal if the failure was not
    // handled properly in the function call.
    auto code = static_cast<firebase::functions::Error>(future.error());

    // Display the error in the UI.
    DisplayError(code, future.error_message());
    return;
  }

  const firebase::functions::HttpsCallableResult* result = future.result();
  firebase::Variant data = result->data();
  // This will assert if the result returned from the function wasn't a string.
  std::string message = data.string_value();
  // Display the result in the UI.
  DisplayResult(message);
}

// ...

// ...
  auto future = AddMessage(message);
  future.OnCompletion(OnAddMessageCallback);
  // ...

단일성

 addMessage(text).ContinueWith((task) => {
  if (task.IsFaulted) {
    foreach (var inner in task.Exception.InnerExceptions) {
      if (inner is FunctionsException) {
        var e = (FunctionsException) inner;
        // Function error code, will be INTERNAL if the failure
        // was not handled properly in the function call.
        var code = e.ErrorCode;
        var message = e.ErrorMessage;
      }
    }
  } else {
    string result = task.Result;
  }
});

앱을 실행하기 전에 앱만 호출 가능한 함수 엔드포인트에 액세스할 수 있도록 앱 체크 를 활성화해야 합니다.