Check out what’s new from Firebase at Google I/O 2022. Learn more

管理 Firebase 安裝

Firebase 安裝服務 (FIS) 為每個已安裝的 Firebase 應用實例提供一個 Firebase 安裝 ID (FID)。這些 Firebase 服務在內部使用 Firebase 安裝 ID:

Firebase 服務Firebase 安裝功能
Firebase 雲消息傳遞

Firebase 雲消息傳遞使用 Firebase 安裝 ID 來定位設備以進行消息傳遞。

Firebase 應用內消息

Firebase 應用內消息傳遞使用 Firebase 安裝 ID 來定位設備以進行消息傳遞。

Firebase 性能監控

性能監控使用 Firebase 安裝 ID 來計算訪問網絡資源的唯一 Firebase 安裝數量,以確保訪問模式足夠匿名。它還使用 Firebase 安裝 ID 和 Firebase 遠程配置來管理性能事件報告的速率。

Google Analytics for Firebase

Google Analytics for Firebase 使用這些數據來提供分析和歸因信息。收集的精確信息可能因設備和環境而異。

Firebase 遠程配置

遠程配置使用 Firebase 安裝 ID 選擇配置值以返回給最終用戶設備。

Firebase 機器學習

Firebase ML 在與應用實例交互時使用稱為安裝身份驗證令牌的憑據進行設備身份驗證,例如,將開發人員模型分發到應用實例。

通常,Firebase 服務使用 Firebase 安裝服務,而無需開發人員直接與 FIS API 交互。但是,在某些情況下,應用程序開發人員可能希望直接調用 FIS API,例如:

  • 刪除 Firebase 安裝和與安裝相關的數據。
  • 檢索標識符(Firebase 安裝 ID)以定位特定的應用安裝。
  • 檢索安裝身份驗證令牌以對 Firebase 安裝進行身份驗證。

要開始直接調用 FIS API,請將 SDK 添加到您的應用程序中。

將 Firebase 安裝 SDK 添加到您的應用

iOS+

  1. 將 Firebase 安裝的依賴項添加到您的 Podfile:
    pod 'FirebaseInstallations'
  2. 運行pod install並打開創建的.xcworkspace文件。
  3. 在您的UIApplicationDelegate中導入FirebaseCore模塊,以及您的應用委託使用的任何其他Firebase 模塊。例如,要使用 Cloud Firestore 和身份驗證:

    迅速

    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

    Objective-C

    @import FirebaseCore;
    @import FirebaseFirestore;
    @import FirebaseAuth;
    // ...
          
  4. 配置FirebaseApp共享實例,通常在App的初始化程序或應用委託的application(_:didFinishLaunchingWithOptions:)方法中:

    迅速

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

    Objective-C

    // Use Firebase library to configure APIs
    [FIRApp configure];

安卓

將 Firebase 安裝 Android SDK 的依賴項添加到您的模塊(應用級)Gradle 文件(通常是app/build.gradle ):

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

JavaScript

根據您的 Web 應用程序的託管方式,您的配置可能會自動處理,或者您可能需要更新Firebase 配置對象

例如,如果您的依賴項添加在 index.html 中,請在 <head> 元素中添加依賴項:

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

  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 時,與該安裝 ID 關聯的數據會在 180 天內從所有使用 Firebase 安裝 ID 識別安裝的 Firebase 服務的實時和備份系統中移除。 Google關於刪除和保留的聲明中對這一過程進行了高級描述。

除非您在應用程序中禁用所有 FID 生成服務,否則 FIS 會在幾天內創建一個新 ID。 Firebase 將新創建的 ID 視為新的 Firebase 安裝,並且不會以任何方式將其與之前的 ID 或數據相關聯。

使用客戶端 API 調用刪除 FID

要刪除 Firebase 服務生成的 FID,請從 Firebase 安裝 SDK 調用相應的方法:

迅速

Installations.installations().delete { error in
  if let error = error {
    print("Error deleting installation: \(error)")
    return
  }
  print("Installation deleted");
}

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+KTX

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,這些方法反映的是實例 ID 命名。但是,當使用任何當前 Firebase 調用時,它們實際上都會刪除 FID開發工具包)。

節點.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)

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 並立即使用具有新的、不相關的 ID 的 Firebase 服務,請使用客戶端 API 來處理刪除。

檢索客戶端標識符

如果您需要識別應用的特定安裝,可以通過檢索 Firebase 安裝 ID 來實現。例如,要在 Firebase 應用內消息開發期間執行測試,您可以使用其 Firebase 安裝 ID 識別和定位正確的測試設備。

要檢索 Firebase 安裝 ID:

迅速

Installations.installations().installationID { (id, error) in
  if let error = error {
    print("Error fetching id: \(error)")
    return
  }
  guard let id = id else { return }
  print("Installation ID: \(id)")
}

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+KTX

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 安裝進行身份驗證。例如,在為遠程配置設計 A/B 測試時,您可以使用安裝身份驗證令牌對目標測試設備進行身份驗證。

安裝身份驗證令牌是 JSON Web 令牌 (JWT) 格式的短期不記名令牌,其中包含以下安裝信息:

  • Firebase 安裝 ID
  • 關聯項目 ( projectNumber )
  • 關聯的 Firebase 應用程序 ID ( appId )
  • 令牌的到期日期

安裝授權令牌不能被撤銷,並且在其到期日期之前一直有效。默認令牌生命週期為一周。

要檢索安裝身份驗證令牌:

迅速

Installations.installations().authTokenForcingRefresh(true, completion: { (result, error) in
  if let error = error {
    print("Error fetching token: \(error)")
    return
  }
  guard let result = result else { return }
  print("Installation auth token: \(result.authToken)")
})

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+KTX

FirebaseInstallations.getInstance().getToken(/* forceRefresh */ true)
    .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 的情況:

  • 卸載或重新安裝應用程序,例如當最終用戶在新設備上安裝時。
  • 最終用戶清除應用或設備的緩存。
  • 由於應用不活動(當前的閾值是 270 天不活動),在後端觸發 FID 刪除。

當應用程序在這些情況下遇到 FID 輪換或刪除時,它們會被分配一個新的 FID。此外,與已刪除 FID 關聯的安裝身份驗證令牌將被刪除,無論其自身成熟度如何,並替換為新的安裝身份驗證令牌。

應用程序可以監控這些變化並做出相應的響應。

要監控 FID 輪換:

迅速

installationIDObserver = NotificationCenter.default.addObserver(
        forName: .InstallationIDDidChange,
        object: nil,
        queue: nil
) { (notification) in
  // Fetch new Installation ID
  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。

安卓

Kotlin 和 Java 客戶端應添加重試邏輯以響應失敗的調用以檢索新的 FID。

JavaScript

Web 應用程序可以訂閱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 來識別應用安裝。與 Instance ID 相比,Firebase 安裝在可靠性、性能和安全性方面具有顯著優勢。依賴 Instance ID SDK 的 Firebase 應用應遷移到 Firebase 安裝。

遷移過程因您的應用而異:

  • 不直接調用 Instance ID API 的應用可以通過更新其 SDK 版本進行遷移。大多數 Firebase 應用都屬於這一類。

  • 明確對實例 ID 進行 API 調用的應用必須更新 SDK 版本進行代碼更改,以將實例 ID 方法替換為其 Firebase 安裝或 FCM 等效項。如果您的應用程序使用實例 ID 來檢索 FCM 註冊令牌或明確使用實例 ID 來定位應用程序實例或用於任何其他目的,您將需要更新您的應用程序代碼。

目前,FIS 與舊標識符 Firebase Instance ID 向後兼容。刪除 IID是使用這些 Firebase SDK 請求數據刪除的另一種方法:

  • iOS 6.14.0 及更低版本
  • 早於 2020 年 2 月 27 日的 Android SDK

這意味著應用不需要遷移到 Firebase 安裝;但是,強烈建議這樣做。

為 Firebase 安裝升級到最低 SDK 版本

要從實例 ID 遷移到 Firebase 安裝,請確保您的應用程序至少使用以下 Firebase SDK 列出的最低版本號:

Firebase SDK最低安卓版本最低 iOS 版本
Firebase 雲消息傳遞v20.3.0 v6.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
崩潰分析器v17.2.1 v6.23.0
機器學習套件v22.1.2 v6.28.0

更新顯式調用實例 ID API 的代碼

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

檢索標識符

獲取實例 ID 的方法被替換為獲取安裝 ID 的方法。例如:

迅速

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+KTX

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

迅速

Installations.installations().installationID { (id, error) in
  if let error = error {
    print("Error fetching id: \(error)")
    return
  }
  guard let id = id else { return }
  print("Installation ID: \(id)")
}

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+KTX

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 的方法已替換為刪除 Firebase 安裝 ID 的方法。例如:

迅速

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

安卓

FirebaseInstanceId.deleteInstanceId();

迅速

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+KTX

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+KTX

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()
        })

迅速

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+KTX

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()
})

迅速

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;
  }
}];