管理 Firebase 安裝作業

Firebase 安裝服務 (FIS) 會為 Firebase 應用程式的每個已安裝例項提供 Firebase 安裝 ID (FID)。Firebase 安裝 ID 會由下列 Firebase 服務在內部使用:

Firebase 服務 Firebase 安裝功能
Firebase Cloud Messaging

Firebase Cloud Messaging 會使用 Firebase 安裝 ID 指定裝置,以便傳送訊息。

Firebase Crashlytics

Firebase Crashlytics 會根據應用程式執行個體的 Firebase 安裝 ID 變更,輪替 Crashlytics 安裝作業 UUID。日後,安裝 ID 可能會用於啟用可強化當機回報和當機管理服務的功能。

Firebase In-App Messaging

Firebase In-App Messaging 會使用 Firebase 安裝 ID 指定裝置,以便傳送訊息。

Firebase Performance Monitoring

Performance Monitoring 會使用 Firebase 安裝 ID 計算存取網路資源的獨特 Firebase 安裝數,以確保存取模式足夠匿名。它也會使用 Firebase 安裝 ID 搭配 Firebase Remote Config 來管理成效事件回報率。

Firebase Remote Config

Remote Config 會使用 Firebase 安裝 ID 選取要傳回至使用者裝置的設定值。

Firebase ML

Firebase ML 會在與應用程式執行個體互動時,使用稱為 安裝驗證權杖的憑證進行裝置驗證,例如將開發人員模型發布至應用程式執行個體。

Firebase 使用者區隔儲存空間

Firebase 使用者區隔儲存空間會儲存 Firebase 安裝 ID 和相關屬性及區隔,為使用這些資訊的其他 Firebase 服務提供指定目標資訊。

一般來說,Firebase 服務會使用 Firebase 安裝服務,而不需要開發人員直接與 FIS API 互動。不過,在某些情況下,應用程式開發人員可能會想要直接呼叫 FIS API,例如:

  • 如何刪除 Firebase 安裝項目和與安裝項目相關聯的資料。
  • 擷取 ID (Firebase 安裝 ID),以便指定特定應用程式安裝。
  • 擷取安裝驗證權杖,以便驗證 Firebase 安裝。

如要開始直接呼叫 FIS API,請將 SDK 新增至應用程式。

在應用程式中加入 Firebase 安裝 SDK

iOS+

  1. Firebase 安裝作業的依附元件新增至 Podfile:
    pod 'FirebaseInstallations'
  2. 執行 pod install,並開啟已建立的 .xcworkspace 檔案。
  3. UIApplicationDelegate 中匯入 FirebaseCore 模組,以及應用程式委派程式使用的任何其他 Firebase 模組。例如,如要使用 Cloud FirestoreAuthentication

    SwiftUI

    import SwiftUI
    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

    Swift

    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

    Objective-C

    @import FirebaseCore;
    @import FirebaseFirestore;
    @import FirebaseAuth;
    // ...
          
  4. 在應用程式委派作業的 application(_:didFinishLaunchingWithOptions:) 方法中,設定 FirebaseApp 共用例項:

    SwiftUI

    // Use Firebase library to configure APIs
    FirebaseApp.configure()

    Swift

    // Use Firebase library to configure APIs
    FirebaseApp.configure()

    Objective-C

    // Use Firebase library to configure APIs
    [FIRApp configure];
  5. 如果您使用 SwiftUI,則必須建立應用程式委派程式,並透過 UIApplicationDelegateAdaptorNSApplicationDelegateAdaptor 將其附加至 App 結構體。您也必須停用應用程式委派程式 swizzling。詳情請參閱 SwiftUI 操作說明

    SwiftUI

    @main
    struct YourApp: App {
      // register app delegate for Firebase setup
      @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
      var body: some Scene {
        WindowGroup {
          NavigationView {
            ContentView()
          }
        }
      }
    }
          

Android

Firebase 安裝 Android SDK 的依附元件新增至模組 (應用程式層級) Gradle 檔案 (通常為 app/build.gradle):

implementation 'com.google.firebase:firebase-installations:18.0.0'

JavaScript

視網頁應用程式的託管方式而定,系統可能會自動處理設定,或是您可能需要更新 Firebase 設定物件

舉例來說,如果您在 index.html 中新增依附元件,請在 <head> 元素中新增依附元件:

<script src="/__/firebase/11.0.2/firebase-installations.js"></script>

Flutter

  1. 在 Flutter 專案的根目錄中執行下列指令,安裝 Firebase 安裝外掛程式:

    flutter pub add firebase_app_installations
    
  2. 重建專案:

    flutter run
    
  3. 匯入 Firebase 安裝外掛程式:

    import 'package:firebase_app_installations/firebase_app_installations.dart';
    

刪除 Firebase 安裝

Firebase 安裝作業相關聯的資料通常「不會」識別個人身分。不過,為使用者提供管理及刪除這類資料的選項還是很有幫助。

每個應用程式的每個安裝作業都有不同的 Firebase 安裝 ID;同一部裝置上的不同應用程式會有不同的 Firebase 安裝 ID。Firebase 安裝 ID 可識別應用程式安裝作業,以及與這些應用程式安裝作業相關聯的資料。

刪除安裝 ID 後,系統會在 180 天內,從所有使用 Firebase 安裝 ID 來識別安裝的 Firebase 服務的實際和備份系統中,移除與該安裝 ID 相關聯的資料。Google 的資料刪除與資料保留聲明中概略說明瞭這項程序。

除非您在應用程式中停用所有 FID 產生服務,否則 FIS 會在幾天內建立新的 ID。Firebase 會將新建立的 ID 視為新的 Firebase 安裝,且不會以任何方式將其與先前的 ID 或資料建立關聯。

透過用戶端 API 呼叫刪除 FID

如要刪除 Firebase 服務產生的 FID,請從 Firebase 安裝 SDK 呼叫適當的方法:

Swift

do {
  try await Installations.installations().delete()
  print("Installation deleted");
} catch {
  print("Error deleting installation: \(error)")
}

Objective-C

[[FIRInstallations installations] deleteWithCompletion:^(NSError *error) {
   if (error != nil) {
     NSLog(@"Error deleting Installation %@", error);
     return;
   }
   NSLog(@"Installation deleted");
}];

Java

FirebaseInstallations.getInstance().delete()
        .addOnCompleteListener(new OnCompleteListener<Void>() {
    @Override
    public void onComplete(@NonNull Task<Void> task) {
        if (task.isSuccessful()) {
            Log.d("Installations", "Installation deleted");
        } else {
            Log.e("Installations", "Unable to delete Installation");
        }
    }
});

Kotlin

FirebaseInstallations.getInstance().delete().addOnCompleteListener { task ->
    if (task.isComplete) {
        Log.d("Installations", "Installation deleted")
    } else {
        Log.e("Installations", "Unable to delete Installation")
    }
}

JavaScript

await firebase.installations().delete();

Dart

await FirebaseInstallations.instance.delete();

透過伺服器 API 呼叫刪除 FID

如要透過伺服器 API 呼叫刪除 FID,請將 Firebase Admin SDK 新增至伺服器 (如果尚未新增)。

新增 SDK 後,請使用所選語言呼叫刪除函式,刪除 FID (注意:除了 Node.js 以外,這些方法都會反映 Instance ID 命名方式。不過,當使用任何目前的 Firebase SDK 呼叫時,這些方法都會刪除 FID。

Node.js

// An FIDsent from a client service SDK
const idToDelete = 'eyJhbGciOiJFUzI1N_iIs5';

admin.installations().deleteInstallation(idToDelete);

Java

// An FID sent from a client service SDK
String idToDelete = "eyJhbGciOiJFUzI1N_iIs5";

FirebaseInstanceId.getInstance().deleteInstanceIdAsync(idToDelete).get();

Python

  from firebase_admin import instance_id

  # An FID sent from a client service SDK
  id_to_delete = 'eyJhbGciOiJFUzI1N_iIs5'

  instance_id.delete_instance_id(id_to_delete)

Go

client, err := app.InstanceId(ctx)
if err != nil {
  log.Fatalln("error initializing client", err)
}

iidToDelete := "eyJhbGciOiJFUzI1N_iIs5"
if err := client.DeleteInstanceId(ctx, iidToDelete); err != nil {
  log.Fatalln("error deleting FID", err)
}

當您使用伺服器 API 呼叫刪除 Firebase 安裝 ID 時,Firebase 服務會啟動刪除與該安裝 ID 相關聯的資料程序,在 1 到 2 天內停止接受該 ID 的新資料,然後通知用戶端應用程式已刪除該 ID。在 Firebase 通知用戶端應用程式之前,部分應用程式服務可能仍會指定 ID。舉例來說,Firebase 安裝作業可能會在幾小時內持續收到 FCM 通知。

如果您想刪除目前的 Firebase 安裝 ID,並立即使用 Firebase 服務搭配新的不相關 ID,請使用用戶端 API 處理刪除作業。

擷取用戶端 ID

如果您需要識別應用程式的特定安裝作業,可以擷取 Firebase 安裝 ID。舉例來說,如果您想為 BigQuery 匯入作業建立應用程式安裝區隔,或是在 Firebase In-App Messaging 開發期間執行測試,可以使用對應的 Firebase 安裝 ID 識別並指定正確的裝置。

如要擷取 Firebase 安裝 ID,請按照下列步驟操作:

Swift

do {
  let id = try await Installations.installations().installationID()
  print("Installation ID: \(id)")
} catch {
  print("Error fetching id: \(error)")
}

Objective-C

[[FIRInstallations installations] installationIDWithCompletion:^(NSString *identifier, NSError *error) {
  if (error != nil) {
    NSLog(@"Error fetching Installation ID %@", error);
    return;
  }
  NSLog(@"Installation ID: %@", identifier);
}];

Java

FirebaseInstallations.getInstance().getId()
        .addOnCompleteListener(new OnCompleteListener<String>() {
    @Override
    public void onComplete(@NonNull Task<String> task) {
        if (task.isSuccessful()) {
            Log.d("Installations", "Installation ID: " + task.getResult());
        } else {
            Log.e("Installations", "Unable to get Installation ID");
        }
    }
});

Kotlin

FirebaseInstallations.getInstance().id.addOnCompleteListener { task ->
    if (task.isSuccessful) {
        Log.d("Installations", "Installation ID: " + task.result)
    } else {
        Log.e("Installations", "Unable to get Installation ID")
    }
}

JavaScript

const installationId = await firebase.installations().getId();
console.log(installationId);

Dart

String id = await FirebaseInstallations.instance.getId();

擷取安裝驗證權杖

Firebase 服務可使用從 FIS 擷取的驗證權杖驗證 Firebase 安裝作業。舉例來說,為 Remote Config 設計 A/B 版本測試時,您可以使用安裝驗證權杖驗證指定的測試裝置。

安裝授權權杖是 JSON Web Token (JWT) 格式的短效權杖,其中包含安裝作業的下列資訊:

  • Firebase 安裝 ID
  • 相關聯的專案 (projectNumber)
  • 相關聯的 Firebase 應用程式 ID (appId)
  • 權杖的到期日

安裝授權權杖無法撤銷,且會在到期日之前保持有效。憑證的預設效期為一週。

如要擷取安裝驗證權杖,請按照下列步驟操作:

Swift

do {
  let result = try await Installations.installations()
    .authTokenForcingRefresh(true)
  print("Installation auth token: \(result.authToken)")
} catch {
  print("Error fetching token: \(error)")
}

Objective-C

[[FIRInstallations installations] authTokenForcingRefresh:true
                                               completion:^(FIRInstallationsAuthTokenResult *result, NSError *error) {
  if (error != nil) {
    NSLog(@"Error fetching Installation token %@", error);
    return;
  }
  NSLog(@"Installation auth token: %@", [result authToken]);
}];

Java

FirebaseInstallations.getInstance().getToken(/* forceRefresh */true)
        .addOnCompleteListener(new OnCompleteListener<InstallationTokenResult>() {
    @Override
    public void onComplete(@NonNull Task<InstallationTokenResult> task) {
        if (task.isSuccessful() && task.getResult() != null) {
            Log.d("Installations", "Installation auth token: " + task.getResult().getToken());
        } else {
            Log.e("Installations", "Unable to get Installation auth token");
        }
    }
});

Kotlin

val forceRefresh = true
FirebaseInstallations.getInstance().getToken(forceRefresh)
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            Log.d("Installations", "Installation auth token: " + task.result?.token)
        } else {
            Log.e("Installations", "Unable to get Installation auth token")
        }
    }

JavaScript

const installationToken = await firebase.installations()
    .getToken(/* forceRefresh */ true);
console.log(installationToken);

Dart

String token = await FirebaseInstallations.instance.getToken();

監控 Firebase 安裝 ID 生命週期

在應用程式正常運作期間,Firebase 安裝 ID (FID) 不需要特別監控。不過,明確擷取及使用 FID 的應用程式應加入邏輯,以監控 FID 的潛在刪除或輪替情形。以下列舉幾種可刪除或輪替 FID 的情況:

  • 解除安裝或重新安裝應用程式,例如使用者在新裝置上安裝應用程式。
  • 使用者清除應用程式或裝置的快取。
  • 由於應用程式閒置,系統會在後端觸發 FID 刪除作業 (目前的門檻為閒置 270 天)。

在這些情況下,如果應用程式發生 FID 輪替或刪除的情形,系統會為其指派新的 FID。此外,與已刪除的 FID 相關聯的安裝授權權杖也會一併刪除,無論其自身的成熟度為何,並由新的安裝授權權杖取代。

應用程式可以監控這些變化,並做出相應回應。

如要監控 FID 輪替,請按照下列步驟操作:

Swift

installationIDObserver = NotificationCenter.default.addObserver(
        forName: .InstallationIDDidChange,
        object: nil,
        queue: nil
) { (notification) in
  // Fetch new Installation ID
  Task {
    await self.fetchInstallationToken()
  }
}

Objective-C

__weak __auto_type weakSelf = self;
self.installationIDObserver = [[NSNotificationCenter defaultCenter]
        addObserverForName: FIRInstallationIDDidChangeNotification
                    object:nil
                     queue:nil
                usingBlock:^(NSNotification * _Nonnull notification) {
    // Fetch new Installation ID
    [weakSelf fetchInstallationsID];
}];

每當指派新的 FID 時,系統就會將名為 NSNotificationName.InstallationIDDidChange 的 NSNotification 張貼至預設 NSNotificationCenter。

Android

Kotlin 和 Java 用戶端應新增重試邏輯,以便在回應失敗的呼叫時,擷取新的 FID。

JavaScript

網頁應用程式可以訂閱 onIdChange 鉤子。

每次建立新的 FID 時,系統都會觸發已訂閱的回呼:

await firebase.installations().onIdChange((newId) => {
  console.log(newId);
  // TODO: Handle new installation ID.
});

Dart

FirebaseInstallations.instance.onIdChange.listen((token) {
  print('FID token: $token');
});

從執行個體 ID 遷移至 Firebase 安裝

在推出 Firebase 安裝之前,Firebase 會使用 Instance ID SDK 來取得應用程式安裝的 ID。Firebase 安裝程式在可靠性、效能和安全性方面,比 Instance ID 更具優勢。依賴 Instance ID SDK 的 Firebase 應用程式應遷移至 Firebase 安裝。

遷移程序會因應用程式而異:

  • 如果應用程式未直接呼叫 Instance ID API,則可更新 SDK 版本來遷移。大多數 Firebase 應用程式都屬於這個類別。

  • 明確對 Instance ID 發出 API 呼叫的應用程式必須更新 SDK 版本,並變更程式碼,將 Instance ID 方法替換為 Firebase 安裝或 FCM 等同物。如果您的應用程式使用執行個體 ID 來擷取 FCM 註冊權杖,或是明確使用執行個體 ID 指定應用程式執行個體或用於其他用途,您就需要更新應用程式程式碼。

目前,FIS 與舊版 ID Firebase 執行個體 ID 相容。刪除 IID 是透過下列 Firebase SDK 要求刪除資料的替代方法:

  • iOS 6.14.0 以下版本
  • 2020 年 2 月 27 日前的 Android SDK

也就是說,應用程式不需要遷移至 Firebase 安裝作業;不過,我們強烈建議您這麼做。

升級至 Firebase 安裝作業的最低 SDK 版本

如要從 Instance ID 遷移至 Firebase 安裝作業,請確認應用程式至少使用下列 Firebase SDK 的最低版本號碼:

Firebase SDK 最低 Android 版本 最低 iOS 版本
Firebase 雲端通訊 20.3.0 版 6.34.0 版
遠端設定 v19.2.0 v6.24.0
Google Analytics for Firebase (評估 SDK) v17.4.4 v6.18.0
應用程式內通訊 v19.0.7 v6.24.0
效能監控 v19.0.8 v6.21.0
Crashlytics v17.2.1 v6.23.0
ML Kit v22.1.2 v6.28.0

更新明確呼叫 Instance ID API 的程式碼

如果您的 Android 或 Apple 應用程式直接使用 Instance ID SDK 方法,您可以將該用法替換為 Firebase 安裝 SDK 或 FCM SDK 中的相同替代方案。

擷取 ID

取得執行個體 ID 的方法已改為取得安裝 ID 的方法。例如:

之前

Swift

Messaging.messaging().token { token, error in
  if let error = error {
    print("Error fetching remote FCM registration token: \(error)")
  } else if let token = token {
    print("Remote instance ID token: \(token)")
    self.remoteFCMTokenMessage.text = "Remote FCM registration token: \(token)"
  }
}

Objective-C

[[FIRMessaging messaging] tokenWithCompletion:^(NSString * _Nullable token, NSError * _Nullable error) {
   if (error != nil) {
     NSLog(@"Error fetching the remote FCM registration token: %@", error);
   } else {
     NSLog(@"Remote FCM registration token: %@", token);
     NSString* message =
       [NSString stringWithFormat:@"FCM registration token: %@", token];
     self.remoteFCMTokenMessage.text = message;
   }
 }];

Java

FirebaseInstanceId.getInstance().getInstanceId()
        .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
            @Override
            public void onComplete(@NonNull Task<InstanceIdResult> task) {
                Log.d("IID_TOKEN", task.getResult().getToken());
            }
        });

Kotlin

FirebaseInstanceId.getInstance().instanceId
        .addOnSuccessListener { result ->
            Log.d("IID_TOKEN", result.token)
        }

之後

Swift

do {
  let id = try await Installations.installations().installationID()
  print("Installation ID: \(id)")
} catch {
  print("Error fetching id: \(error)")
}

Objective-C

[[FIRInstallations installations] installationIDWithCompletion:^(NSString *identifier, NSError *error) {
  if (error != nil) {
    NSLog(@"Error fetching Installation ID %@", error);
    return;
  }
  NSLog(@"Installation ID: %@", identifier);
}];

Java

FirebaseInstallations.getInstance().getId()
        .addOnCompleteListener(new OnCompleteListener<String>() {
    @Override
    public void onComplete(@NonNull Task<String> task) {
        if (task.isSuccessful()) {
            Log.d("Installations", "Installation ID: " + task.getResult());
        } else {
            Log.e("Installations", "Unable to get Installation ID");
        }
    }
});

Kotlin

FirebaseInstallations.getInstance().id.addOnCompleteListener { task ->
    if (task.isSuccessful) {
        Log.d("Installations", "Installation ID: " + task.result)
    } else {
        Log.e("Installations", "Unable to get Installation ID")
    }
}

刪除 ID

刪除執行個體 ID 的方法已改為刪除 Firebase 安裝 ID 的方法。例如:

之前

Swift

InstanceID.instanceID().deleteID { error in
  if let error = error {
    print("Error deleting instance ID: \(error)")
  }
}

Objective-C

[FIRInstanceID instanceID] deleteIDWithHandler:^(NSError *error) {
  if error != nil {
    NSLog(@"Error deleting instance ID: %@", error);
  }
}];

Android

FirebaseInstanceId.deleteInstanceId();

之後

Swift

func delete(completion: @escaping (Error?) -> Void)

Objective-C

- (void)deleteWithCompletion:(nonnull void (^)(NSError *_Nullable))completion;

Java

FirebaseInstallations.getInstance().delete()
        .addOnCompleteListener(new OnCompleteListener<Void>() {
    @Override
    public void onComplete(@NonNull Task<Void> task) {
        if (task.isSuccessful()) {
            Log.d("Installations", "Installation deleted");
        } else {
            Log.e("Installations", "Unable to delete Installation");
        }
    }
});

Kotlin

FirebaseInstallations.getInstance().delete().addOnCompleteListener { task ->
    if (task.isComplete) {
        Log.d("Installations", "Installation deleted")
    } else {
        Log.e("Installations", "Unable to delete Installation")
    }
}

擷取 FCM 註冊權杖

在導入 Firebase 安裝項目之前,FCM 用戶端會從 Instance ID 擷取註冊符記。FCM SDK 現在提供方法,可用於擷取註冊權杖。

之前

Java

FirebaseInstanceId.getInstance().getInstanceId()
        .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
            @Override
            public void onComplete(@NonNull Task<InstanceIdResult> task) {
                if (!task.isSuccessful()) {
                    Log.w(TAG, "getInstanceId failed", task.getException());
                    return;
                }

                // Get new Instance ID token
                String token = task.getResult().getToken();

                // Log and toast
                String msg = getString(R.string.msg_token_fmt, token);
                Log.d(TAG, msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });

Kotlin

FirebaseInstanceId.getInstance().instanceId
        .addOnCompleteListener(OnCompleteListener { task ->
            if (!task.isSuccessful) {
                Log.w(TAG, "getInstanceId failed", task.exception)
                return@OnCompleteListener
            }

            // Get new Instance ID token
            val token = task.result?.token

            // Log and toast
            val msg = getString(R.string.msg_token_fmt, token)
            Log.d(TAG, msg)
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        })

Swift

Messaging.messaging().token { token, error in
  if let error = error {
    print("Error fetching remote FCM registration token: \(error)")
  } else if let token = token {
    print("Remote instance ID token: \(token)")
    self.remoteFCMTokenMessage.text = "Remote FCM registration token: \(token)"
  }
}

Objective-C

[[FIRMessaging messaging] tokenWithCompletion:^(NSString * _Nullable token, NSError * _Nullable error) {
   if (error != nil) {
     NSLog(@"Error fetching the remote FCM registration token: %@", error);
   } else {
     NSLog(@"Remote FCM registration token: %@", token);
     NSString* message =
       [NSString stringWithFormat:@"FCM registration token: %@", token];
     self.remoteFCMTokenMessage.text = message;
   }
 }];

之後

Java

FirebaseMessaging.getInstance().getToken()
    .addOnCompleteListener(new OnCompleteListener<String>() {
        @Override
        public void onComplete(@NonNull Task<String> task) {
          if (!task.isSuccessful()) {
            Log.w(TAG, "Fetching FCM registration token failed", task.getException());
            return;
          }

          // Get new FCM registration token
          String token = task.getResult();

          // Log and toast
          String msg = getString(R.string.msg_token_fmt, token);
          Log.d(TAG, msg);
          Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
        }
    });

Kotlin

FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
        Log.w(TAG, "Fetching FCM registration token failed", task.exception)
        return@OnCompleteListener
    }

    // Get new FCM registration token
    val token = task.result

    // Log and toast
    val msg = getString(R.string.msg_token_fmt, token)
    Log.d(TAG, msg)
    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
})

Swift

Messaging.messaging().token { token, error in
  if let error = error {
    print("Error fetching FCM registration token: \(error)")
  } else if let token = token {
    print("FCM registration token: \(token)")
    self.fcmRegTokenMessage.text  = "Remote FCM registration token: \(token)"
  }
}

Objective-C

[[FIRMessaging messaging] tokenWithCompletion:^(NSString *token, NSError *error) {
  if (error != nil) {
    NSLog(@"Error getting FCM registration token: %@", error);
  } else {
    NSLog(@"FCM registration token: %@", token);
    self.fcmRegTokenMessage.text = token;
  }
}];