5

我正在构建一个由 Firebase 应用支持的 Android 应用,并且我希望能够创建一个可以编辑或删除其他用户帐户的管理员帐户。如果我理解正确,Firebase Admin SDK 应该允许我这样做。所以我按照这里的说明进行操作。

在我的应用程序中设置 Admin SDK。我在 build.app 中添加了以下内容:

compile 'com.google.firebase:firebase-admin:4.1.1'

在我的应用程序类中,我添加了这个:

FileInputStream serviceAccount = null;
try {
    serviceAccount = new FileInputStream("app/<MY-DATABASE>.json");
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

if (serviceAccount != null) {
    FirebaseOptions options = new FirebaseOptions.Builder()
            .setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
            .setDatabaseUrl("https://<MY-APP>.firebaseio.com/")
            .build();

    FirebaseApp.initializeApp(options);
}

但是,它告诉我:

  • FirebaseOptions.Builder 中没有名为 setCredential() 的方法,并且
  • FirebaseApp.initializeApp() 采用 Context 对象,而不是 FirebaseOptions。

根据文档,FirebaseOptions.Builder.setCredential()是一种新方法,它取代了弃用的FirebaseOptions.Builder.setServiceAccount(). 但setServiceAccount()也不存在。

这里发生了什么?

4

3 回答 3

11

您不能在 Android 应用中与 Firebase Android 客户端库一起使用 Firebase Admin SDK。SDK 都提供了具有完全相同的包和类名的类,因此它不可能同时使用它们(编译器如何知道您打算将哪一个构建到您的应用程序中?)。

例如,查看 Android 客户端库中 FirebaseOptions Builder 的 javadoc:

com.google.firebase.FirebaseOptions.Builder

现在查看 java Admin SDK 中的同一个类(注意 URL 不同):

com.google.firebase.FirebaseOptions.Builder

您可以亲眼看到它们是不同的东西,即使它们具有相同的名称。因此,您的编译器正在查看 Android SDK 定义,而不是管理 SDK 定义。

正如弗兰克所说,您可能不想在您的 Android 应用程序中使用管理库。如果您想使用管理 SDK,请在您控制的服务器上使用它,并在需要时让您的 Android 应用程序与之通信。

于 2017-02-08T01:24:13.187 回答
1

现在 FirebaseOptions 类取自其他依赖项,您可以使用 exclude 标签从其他依赖项中删除 firebase 组件,如下所示。

compile 'com.google.firebase:firebase-admin:5.8.0' 

compile ('com.google.firebase:firebase-messaging:9.6.1'){
    exclude module: 'firebase-common'
}
compile ('com.google.firebase:firebase-auth:9.6.1'){
    exclude module: 'firebase-common'
}
compile ('com.google.firebase:firebase-database:9.6.1'){
    exclude module: 'firebase-common'
}
compile ('com.firebase:firebase-client-android:2.5.0'){
    exclude module: 'firebase-common'
}
于 2018-02-12T08:40:55.577 回答
0

正如公认的答案所述,将 Firebase Admin 放在使用 Firebase 的 Android 应用中并不是一个好主意,因为存在同名的类。

我想创建一个自定义令牌(https://firebase.google.com/docs/auth/android/custom-auth),所以我最终做了:

1) 创建一个单独的无 UI 的服务器应用程序。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        finish()  // Just end the app here.
    }
}

<resources>
    <style name="AppTheme" parent="@android:style/Theme.NoDisplay">
    </style>
</resources>

2) 将 IntentService 添加到服务器应用程序并生成自定义令牌。

class CustomTokenService : IntentService(CustomTokenService::class.java.simpleName) {
    // Runs in its own thread.
    override fun onHandleIntent(intent: Intent?) {    
        // Initialize FirebaseApp only when not already initialized.
        try {
            FirebaseApp.getInstance()
        } catch (ex: IllegalStateException) {
            try {
                val inputStream = assets.open("serviceAccountKey.json")
                val options = FirebaseOptions.Builder().
                        setCredential(FirebaseCredentials.fromCertificate(inputStream)).
                        setDatabaseUrl("https://YOUR_APP.firebaseio.com/").
                        build()
                FirebaseApp.initializeApp(options)
                inputStream.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }

        // In real life, you should verify ID/PW before creating custom token.
        val id = intent!!.getStringExtra("ID")
        val pw = intent.getStringExtra("PW")

        val additionalClaims = HashMap<String, Any>()
        additionalClaims.put("premiumAccount", true)

        FirebaseAuth.getInstance().createCustomToken(id, additionalClaims).
                addOnSuccessListener { customToken ->
            // Send custom token back to client.
            val resultReceiver = intent.getParcelableExtra<ResultReceiver>(RESULT_RECEIVER)
            val bundle = Bundle()
            bundle.putString(CUSTOM_TOKEN, customToken)
            resultReceiver.send(Activity.RESULT_OK, bundle)
        }
    }
}

请注意,我通过“ResultReceiver”将自定义令牌发送回客户端,但您可以自由使用其他方式,例如“Messenger”或“BroadcastReceiver”。

3)从客户端,我启动驻留在服务器应用程序中的服务。

String MYSERVER = "SERVER_ID";  // e.g. "com.domain.myserver"
String CUSTOM_TOKEN_SERVICE = MYSERVER + ".CustomTokenService";

Intent intent = new Intent();
intent.putExtra("ID", ID);
intent.putExtra("PW", PW);
intent.putExtra(RESULT_RECEIVER, mResultReceiver);
intent.setComponent(new ComponentName(MYSERVER, CUSTOM_TOKEN_SERVICE));
getContext().startService(intent);

4) 当我从服务器应用程序收到自定义令牌时,我登录到 Firebase。

ResultReceiver resultReceiver = new ResultReceiver(new Handler()) {
    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {
        String customToken = resultData.getString(CUSTOM_TOKEN);
        mFirebaseAuth.signInWithCustomToken(customToken);
    }
};
Parcel parcel = Parcel.obtain();
resultReceiver.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
mResultReceiver = ResultReceiver.CREATOR.createFromParcel(parcel);
parcel.recycle();

5) 和 Gradle 配置文件。

buildscript {
    ext.kotlin_version = '1.2.21'
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

---------------------------------------------------------------------------
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 26

    defaultConfig {
        applicationId "org.solamour.myserver"
        minSdkVersion 14
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        multiDexEnabled true

        javaCompileOptions {
            annotationProcessorOptions {
                includeCompileClasspath false
            }
        }
        resConfigs "auto"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    // Conflict with dependency 'com.google.code.findbugs:jsr305' in project ':app'.
    // Resolved versions for app (1.3.9) and test app (2.0.1) differ.
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:2.0.1'    // Or "1.3.9".
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'

    implementation 'com.google.firebase:firebase-admin:4.1.6'
    implementation 'com.android.support:multidex:1.0.2'
}

我能够使用的最高 Firebase Admin 版本是“4.1.6”;之后的任何事情都涉及对 gradle 文件的大量修改(而且结果也不是很好)。

于 2017-11-08T04:23:11.573 回答