Google Play分发应用Firestore指定字段返回空值,本地调试正常
问题描述
我的应用目前仅在Google Play内部测试轨道发布,通过Android Studio启动运行无异常,但上传至Google Play后,卸载手机上的版本再下载安装,启动时执行以下代码中document.get("Best level")、document.get("Best number of words")、document.get("Best word length")和document.get("Play sounds")均返回null。
相关代码
private static final String FSBESTLEVEL = "Best level"; private static final String FSBESTNUMWORDS = "Best number of words"; private static final String FSBESTWORDLEN = "Best word length"; private static final String FSSOUNDS = "Play sounds"; private void getSettings() { spinner.setVisibility(View.VISIBLE); mDevIDDocRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() { // mDevIDDocRef.get(Source.SERVER).addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() { @Override public void onComplete(@NonNull Task<DocumentSnapshot> task) { if (task.isSuccessful()) { DocumentSnapshot document = task.getResult(); assert document != null; if (document.exists()) { // Handle the legacy Best score field, which was a String. // All the documents that contained a non-blank score have // already been converted to Long. if (document.get(FSBESTSCORE) instanceof String) { updateFieldType(BEGINNER_TIME/1000L); myScore = BEGINNER_TIME/1000; } else { myScore = (Long)document.get(FSBESTSCORE); } level_val = ((Long) Objects.requireNonNull(document.get(FSLEVEL))).intValue(); if (document.get(FSBESTLEVEL) == null) { best_level_val = 0; updateBestLevel(level_val); } else { best_level_val = ((Long)document.get(FSBESTLEVEL)).intValue(); } num_words_val = ((Long) Objects.requireNonNull(document.get(FSNUMWORDS))).intValue(); if (document.get(FSBESTNUMWORDS) == null) { best_num_words_val = 0; updateBestNumwords(num_words_val); } else { best_num_words_val = ((Long)document.get(FSBESTNUMWORDS)).intValue(); } if (document.get(FSBESTWORDLEN) == null) { best_word_length_val = 0; updateBestWordLength(best_word_length_val); } else { best_word_length_val = ((Long)document.get(FSBESTWORDLEN)).intValue(); } word_length_val = ((Long) Objects.requireNonNull(document.get(FSWORDLEN))).intValue(); order_important_val = (boolean) document.get(FSORDER); if (document.get(FSSOUNDS) == null) { play_sounds_val = true; updatePlaySounds(play_sounds_val); } else { play_sounds_val = (boolean) document.get(FSSOUNDS); } uname = (String) document.get(FSUSERNAME); button_continue.setEnabled(true); // If the user name hasn't been set, show the prompt and don't let the user // go to the next page until they've entered one. if (uname == null || uname.length() == 0) { no_screen_name = true; screen_name_prompt.setVisibility(View.VISIBLE); screen_name_fld.setVisibility(View.VISIBLE); } else { no_screen_name = false; screen_name_prompt.setVisibility(View.INVISIBLE); screen_name_fld.setVisibility(View.INVISIBLE); } savePrefs(myScore, level_val, best_level_val, num_words_val, best_num_words_val, word_length_val, best_word_length_val, order_important_val, play_sounds_val, androidID, uname); spinner.setVisibility(View.INVISIBLE); } else { createUserDocument(); } } else { Log.e(TAG, "getSettings() error" + task.getException()); Toast.makeText(context, "getSettings() error" + task.getException(), Toast.LENGTH_LONG).show(); crashlytics.log(Objects.requireNonNull(Objects.requireNonNull(task.getException()).getMessage())); level_val = sharedPref.getInt(FSLEVEL, 0); num_words_val = sharedPref.getInt(FSNUMWORDS, 0); word_length_val = sharedPref.getInt(FSWORDLEN, 0); order_important_val = sharedPref.getBoolean(FSORDER, false); play_sounds_val = sharedPref.getBoolean(FSSOUNDS, true); spinner.setVisibility(View.INVISIBLE); } } }); }
解决方案
1. 补全用户文档初始化逻辑
核心问题大概率是createUserDocument()创建新用户文档时,未初始化FSBESTLEVEL、FSBESTNUMWORDS、FSBESTWORDLEN、FSSOUNDS这些字段。调试时你可能已有包含这些字段的测试文档,所以读取正常;但Google Play新用户首次启动时,文档是全新创建的,缺少字段导致get()返回null。
修改createUserDocument(),添加默认值初始化:
Map<String, Object> userData = new HashMap<>(); userData.put(FSBESTLEVEL, 0); userData.put(FSBESTNUMWORDS, 0); userData.put(FSBESTWORDLEN, 0); userData.put(FSSOUNDS, true); // 其他必要字段初始化... mDevIDDocRef.set(userData);
2. 强制从服务器拉取数据
当前代码注释掉了Source.SERVER参数,默认会优先读取本地缓存(若存在)。恢复该参数可避免潜在的缓存同步问题,确保每次都从服务器获取最新文档:
mDevIDDocRef.get(Source.SERVER).addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
3. 优化字段读取的健壮性
使用Firebase提供的类型安全方法读取字段,直接设置默认值,减少冗余的null判断:
best_level_val = document.getLong(FSBESTLEVEL) != null ? document.getLong(FSBESTLEVEL).intValue() : 0; best_num_words_val = document.getLong(FSBESTNUMWORDS) != null ? document.getLong(FSBESTNUMWORDS).intValue() : 0; best_word_length_val = document.getLong(FSBESTWORDLEN) != null ? document.getLong(FSBESTWORDLEN).intValue() : 0; play_sounds_val = document.getBoolean(FSSOUNDS) != null ? document.getBoolean(FSSOUNDS) : true;
4. 验证Firebase安全规则
确认Firebase数据库规则允许发布版本的应用读取用户文档。调试签名和发布签名的SHA-1不同,需确保两者都添加到Firebase项目的应用设置中,避免权限拦截。
内容的提问来源于stack exchange,提问作者FractalBob
相关产品推荐
相关产品推荐

