2020年3月6日金曜日

Facebook sdk で <meta-data> を設定しているのに初期化されていないと怒られる問題に対応した

いやー、まったくひどい落とし穴でしたよ。

もとの構成はこんな感じです(facebookAppId の値はダミーです)。

build.gradle
  1. android {  
  2.     ...  
  3.     defaultConfig {  
  4.         ...  
  5.         manifestPlaceholders = [facebookAppId: "1234567890000000"]  
  6.     }  
  7.     ...  
  8. }  
  9.   
  10. dependencies {  
  11.     ...  
  12.     implementation "com.facebook.android:facebook-android-sdk:6.1.0"  
  13.     implementation "com.facebook.android:facebook-share:6.1.0"  
  14. }  
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest ...>  
  3.   
  4.     ...  
  5.   
  6.     <application  
  7.         ...>  
  8.   
  9.         ...  
  10.   
  11.         <meta-data  
  12.             android:name="com.facebook.sdk.ApplicationId"  
  13.             android:value="${facebookAppId}" />  
  14.   
  15.         <provider  
  16.             android:name="com.facebook.FacebookContentProvider"  
  17.             android:authorities="com.facebook.app.FacebookContentProvider${facebookAppId}"  
  18.             android:exported="true" />  
  19.   
  20.     </application>  
  21.   
  22. </manifest>  

公式のドキュメント(https://developers.facebook.com/docs/android/getting-started#app_id)には meta-data を AndroidManifest に書けば勝手に初期化処理がされると書いてあるのに、実際に動かすと以下の初期化処理が走っていないというエラーで落ちます。

java.lang.ExceptionInInitializerError
     Caused by: The SDK has not been initialized, make sure to call FacebookSdk.sdkInitialize() first.


調べてみると FacebookSdk の loadDefaultsFromMetadata() の中で meta-data から読みんだ com.facebook.sdk.ApplicationId の値が Float になっていることが判明しました!(facebookAppId が全て数字だからそうなるのでしょうか...)

下記の Object appId が Float になってしまっていたのです。そのためその後の if 文に入らず、applicationId がセットされていませんでした。

FacebookSdk.java
  1. // Package private for testing only  
  2. static void loadDefaultsFromMetadata(Context context) {  
  3.     if (context == null) {  
  4.         return;  
  5.     }  
  6.   
  7.     ApplicationInfo ai = null;  
  8.     try {  
  9.         ai = context.getPackageManager().getApplicationInfo(  
  10.                 context.getPackageName(), PackageManager.GET_META_DATA);  
  11.     } catch (PackageManager.NameNotFoundException e) {  
  12.         return;  
  13.     }  
  14.   
  15.     if (ai == null || ai.metaData == null) {  
  16.         return;  
  17.     }  
  18.   
  19.     if (applicationId == null) {  
  20.         Object appId = ai.metaData.get(APPLICATION_ID_PROPERTY);  
  21.         if (appId instanceof String) {  
  22.             String appIdString = (String) appId;  
  23.             if (appIdString.toLowerCase(Locale.ROOT).startsWith("fb")) {  
  24.                 applicationId = appIdString.substring(2);  
  25.             } else {  
  26.                 applicationId = appIdString;  
  27.             }  
  28.         } else if (appId instanceof Integer) {  
  29.             throw new FacebookException(  
  30.                     "App Ids cannot be directly placed in the manifest." +  
  31.                     "They must be prefixed by 'fb' or be placed in the string resource file.");  
  32.         }  
  33.     }  
  34.   
  35.     ...  
  36. }  
ここの処理を読むと、appId の最初に fb or FB がついているときはそれを省いた部分を applicationId にしていることがわかります。

そこで以下のように meta-data の value を "fb${facebookAppId}" にしたら怒られなくなりました!
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest ...>  
  3.   
  4.     ...  
  5.   
  6.     <application  
  7.         ...>  
  8.   
  9.         ...  
  10.   
  11.         <meta-data  
  12.             android:name="com.facebook.sdk.ApplicationId"  
  13.             android:value="fb${facebookAppId}" />  
  14.   
  15.         <provider  
  16.             android:name="com.facebook.FacebookContentProvider"  
  17.             android:authorities="com.facebook.app.FacebookContentProvider${facebookAppId}"  
  18.             android:exported="true" />  
  19.   
  20.     </application>  
  21.   
  22. </manifest>  



ちなみに facebookAppId を string resource で用意した場合
  1. <string name="facebook_app_id">1234567890000000</string>  
とか
  1. android {  
  2.     ...  
  3.     defaultConfig {  
  4.         ...  
  5.         resValue "string", "facebook_app_id", "1234567890000000"  
  6.     }  
  7.     ...  
  8. }  
のときは、fb を付けなくても com.facebook.sdk.ApplicationId の値は String として読み込まれます。
  1. <meta-data  
  2.     android:name="com.facebook.sdk.ApplicationId"  
  3.     android:value="@string/facebook_app_id" />  




0 件のコメント:

コメントを投稿