Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

管理 Firebase 安装

Firebase 安装服务 (FIS) 会为每个已安装的 Firebase 应用实例提供一个 Firebase 安装 ID (FID)。Firebase 服务(如 In-App Messaging 或 Remote Config)在内部使用此 Firebase 安装 ID,开发者无需直接与 FIS API 进行交互。不过,在某些情况下,应用开发者可能希望直接调用 FIS API,例如:

  • 删除 Firebase 安装以及与安装关联的数据。
  • 检索标识符(Firebase 安装 ID)以定位特定应用安装。
  • 检索安装身份验证令牌以对 Firebase 安装进行身份验证。

如需开始直接调用 FIS API,请将 SDK 添加到您的应用中。

将 Firebase 安装 SDK 添加到您的应用中

iOS

  1. 将 Firebase 安装的依赖项添加到您的 Podfile 中:
    pod 'Firebase/Installations'
  2. 运行 pod install 并打开创建的 .xcworkspace 文件。
  3. UIApplicationDelegate 中导入 Firebase 模块:

    Swift

    import Firebase

    Objective-C

    @import Firebase;
  4. 配置一个 FirebaseApp 共享实例(通常在应用的 application:didFinishLaunchingWithOptions: 方法中配置):

    Swift

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

    Objective-C

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

Android

将 Firebase 安装 Android SDK 的依赖项添加到您的模块(应用级)Gradle 文件(通常为 app/build.gradle)中:

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

JavaScript

您的配置可能会自动进行处理,或者您可能需要更新 Firebase 配置对象,具体取决于您的 Web 应用的托管方式。

例如,如果您的依赖项已添加到 index.html 中,请在 <head> 元素中添加依赖项:

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

删除 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

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

通过服务器 API 调用删除 FID

要通过服务器 API 调用删除 FID,请将 Firebase Admin SDK 添加到您的服务器(如果尚未添加)。

添加 SDK 后,请以您选择的语言通过调用删除函数来删除 FID(请注意:除了 Node.js 之外,这些方法反映的是实例 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 进行删除。

检索客户端标识符

如果您需要识别应用的特定安装,则可以通过检索 Firebase 安装 ID 来实现。例如,如需在 Firebase In-App Messaging 开发期间执行测试,您可以使用 Firebase 安装 ID 来识别和定位正确的测试设备。

如需检索 Firebase 安装 ID,请运行以下命令:

Swift

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

检索安装身份验证令牌

Firebase 服务可以使用从 FIS 检索的身份验证令牌对 Firebase 安装进行身份验证。例如,在为 Remote Config 设计 A/B 测试时,您可以使用安装身份验证令牌对目标测试设备进行身份验证。

安装身份验证令牌是 JSON Web 令牌 (JWT) 格式的短期不记名令牌,其中包含以下安装信息:

  • Firebase 安装 ID
  • 关联项目 (projectNumber)
  • 关联的 Firebase 应用 ID (appId)
  • 令牌的失效日期

安装身份验证令牌无法撤消,有效时间截止到其失效日期。令牌的默认生命周期为一周。

如需检索安装身份验证令牌,请执行以下操作:

Swift

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

监控 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
  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

Web 应用可以订阅 onIdChange 钩子。

每次创建新的 FID 时,都会触发订阅回调:

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

从实例 ID 迁移到 Firebase 安装

在引入 Firebase 安装之前,Firebase 依赖实例 ID SDK 获取应用安装的标识符。Firebase 安装在可靠性、性能和安全性方面远胜于实例 ID。依赖实例 ID SDK 的 Firebase 应用应迁移到 Firebase 安装。

迁移流程因应用而异:

  • 不直接调用实例 ID API 的应用可以通过更新其 SDK 版本进行迁移。大多数 Firebase 应用都属于这一类别。

  • 明确对实例 ID 进行 API 调用的应用必须更新 SDK 版本,更改代码,将实例 ID 方法替换为其 Firebase 安装或 FCM 等效方法。如果您的应用使用实例 ID 来检索 FCM 注册令牌,或者明确使用实例 ID 来定位应用实例或实现任何其他目的,则您需要更新应用代码。

目前,FIS 向后兼容旧版标识符 Firebase 实例 ID。删除 IID 是使用这些 Firebase SDK 请求删除数据的另一种方法:

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

这意味着应用不需要迁移到 Firebase 安装,但我们强烈建议进行迁移。

升级到 Firebase 安装 SDK 最低版本

如需从实例 ID 迁移到 Firebase 安装,请确保您的应用至少使用的是以下列出的 Firebase SDK 的最低版本:

Firebase SDK Android 最低版本 iOS 最低版本
Firebase Cloud Messaging v20.3.0 v6.34.0
Remote Config v19.2.0 v6.24.0
Google Analytics(分析)\ (衡量 SDK) v17.4.4 v6.18.0
In-App Messaging v19.0.7 v6.24.0
Performance Monitoring v19.0.8 v6.21.0
Crashlytics v17.2.1 v6.23.0
ML Kit v22.1.2 v6.28.0

更新明确调用实例 ID API 的代码

如果您的 Android 或 iOS 应用直接使用实例 ID SDK 方法,则可以将该用法替换为 Firebase 安装 SDK 或 FCM SDK 中的相同替代方法。

检索标识符

获取实例 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+KTX

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

之后

Swift

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 的方法。例如:

之前

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+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 客户端会从实例 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()
        })

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

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