xamarin / GooglePlayServicesComponents

Other
315 stars 148 forks source link

Issue with Configuring Firebase Cloud Messaging in Avalonia Cross Platform Android Project #886

Closed aspepper closed 1 month ago

aspepper commented 1 month ago

Hello everyone,

I'm currently working on an Avalonia Cross Platform project for Android and I'm trying to configure Firebase Cloud Messaging (FCM) to receive push notifications. However, I'm encountering an issue where the default FirebaseApp fails to initialize. Below are the details of my setup, including the code I've implemented and the error message I'm receiving.

Project File: AvaloniaApp.Android.csproj

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-android</TargetFramework>
        <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
        <Nullable>enable</Nullable>
        <ApplicationId>com.alexpimenta.AvaloniaApp</ApplicationId>
        <ApplicationVersion>1</ApplicationVersion>
        <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
        <AndroidPackageFormat>apk</AndroidPackageFormat>
        <AndroidEnableProfiledAot>False</AndroidEnableProfiledAot>
    </PropertyGroup>

    <ItemGroup>
        <None Remove="google-services.json" />
        <None Remove="Resources\drawable\ic_stat_ic_notification.png" />
    </ItemGroup>

    <ItemGroup>
        <AndroidResource Include="Icon.png">
            <Link>Resources\drawable\Icon.png</Link>
        </AndroidResource>
    </ItemGroup>

    <ItemGroup>
        <GoogleServicesJson Include="google-services.json" />
    </ItemGroup>

    <ItemGroup>
        <PackageReference Include="Avalonia.Android" Version="11.0.11" />
        <PackageReference Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.9" />
        <PackageReference Include="Xamarin.Firebase.Core" Version="121.1.1.9" />
        <PackageReference Include="Xamarin.Firebase.Messaging" Version="124.0.0" />
        <PackageReference Include="Xamarin.Google.Dagger" Version="2.50.0" />
        <PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.4.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\AvaloniaApp\AvaloniaApp.csproj" />
    </ItemGroup>
</Project>

MainActivity.cs

namespace AvaloniaApp.Android;

[Activity(
    Label = "AvaloniaApp.Android",
    Theme = "@style/MyTheme.NoActionBar",
    Icon = "@drawable/icon",
    MainLauncher = true,
    ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
public class MainActivity : AvaloniaMainActivity<App>
{
    protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
    {
        // Initialize Firebase
        var options = new FirebaseOptions.Builder()
        .SetApplicationId("<FCMApplicationId>")
        .SetApiKey("FCM-ApiKey")
        .SetGcmSenderId("FCM-SenderID")
        .SetProjectId("avaloniaspptestpushnotify")
        .SetStorageBucket("avaloniaapptestpushnotify.appspot.com")
        .Build();

        if (FirebaseApp.GetApps(this).Count == 0)
        {
            FirebaseApp.InitializeApp(this, options);
        }

        // Get the FCM token
        FirebaseInstallations.Instance.GetToken(true).AddOnSuccessListener(new OnTokenSuccessListener());

        return base.CustomizeAppBuilder(builder)
            .WithInterFont()
            .UseReactiveUI();
    }

    public class OnTokenSuccessListener : Java.Lang.Object, IOnSuccessListener
    {
        const string TAG = "OnTokenSuccessListener";

        public void OnSuccess(Java.Lang.Object result)
        {
            FirebaseInstallations firebaseInstallations = FirebaseInstallations.Instance;
            var installId = firebaseInstallations.GetId().Result;
            Log.Debug(TAG, "Firebase Installation ID: " + installId.ToString());

            if (result is InstallationTokenResult tokenResult)
            {
                string token = tokenResult.Token;
                Log.Debug(TAG, "FCM Token: " + token);
                Log.Debug(TAG, "FirebaseApp.Instance.PersistenceKey: " + FirebaseApp.Instance.PersistenceKey);
            }
        }
    }
}

FirebaseService.cs

namespace AvaloniaApp.Android;

public class FirebaseService : FirebaseMessagingService
{
    const string TAG = "FirebaseService";

    public override void OnMessageReceived(RemoteMessage message)
    {
        base.OnMessageReceived(message);

        Log.Debug(TAG, "From: " + message.From);
        Log.Debug(TAG, "Data Values: " + message.Data.Values);

        var notification = message.GetNotification();
        if (notification != null)
        {
            SendNotification(notification.Body, notification.Title, message.Data);
        }
    }

    void SendNotification(string messageBody, string title, IDictionary<string, string> data)
    {
        var intent = new Intent(this, typeof(MainActivity));
        intent.AddFlags(ActivityFlags.ClearTop);
        var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);

        var channelId = "fcm_default_channel";
        var notificationBuilder = new NotificationCompat.Builder(this, channelId)
                                  .SetSmallIcon(Resource.Drawable.notification_action_background)
                                  .SetContentTitle(title)
                                  .SetContentText(messageBody)
                                  .SetAutoCancel(true)
                                  .SetChannelId(channelId)
                                  .SetPriority(2)
                                  .SetContentIntent(pendingIntent);

        var notificationManager = NotificationManagerCompat.From(this);
        notificationManager.Notify(0, notificationBuilder.Build());
    }

    public override void OnNewToken(string token)
    {
        base.OnNewToken(token);
        Log.Debug(TAG, $"OnNewToken - token: {token}");
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    <application android:label="AvaloniaApp" android:icon="@drawable/icon">
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@drawable/ic_stat_ic_notification" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/colorAccent" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="fcm_default_channel" />
        <service
            android:name=".FirebaseService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        <receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
                    android:exported="true"
                    android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

Error Message

When I run the project, I receive the following error message in the output debug:

[FirebaseApp] Default FirebaseApp failed to initialize because no default options were found. This usually means that com.google.gms:google-services was not applied to your gradle project.
[FirebaseInitProvider] FirebaseApp initialization unsuccessful

Problem Description

It seems that the FirebaseApp is not being initialized properly due to missing default options. I've ensured that the google-services.json file is included in the project and is being copied to the correct location during the build process. However, I'm still encountering this issue.

Could anyone provide guidance on what might be wrong with my setup or what additional configuration steps I need to take to resolve this issue?

Thank you in advance for your help!

aspepper commented 1 month ago

I managed to resolve the issue with initializing Firebase in my Avalonia Cross Platform project for Android.

The problem was that the package name entered during the "Add Firebase to your Android app" step in the Firebase Console did not match the namespace of my application. Initially, I used the default package name (e.g., com.company.appname), but my application had a namespace like <ApplicationId>AppUsingPushNotify.Android</ApplicationId>.

By updating the package name in the Firebase Console to match my application's namespace (AppUsingPushNotify.Android), the google-services.json file was generated with the correct package name: "package_name": "AppUsingPushNotify.Android".

After making this change, Firebase initialized successfully when I ran the application.

Here is the corrected setup in my AvaloniaApp.Android.csproj:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-android</TargetFramework>
        <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
        <Nullable>enable</Nullable>
        <ApplicationId>AppUsingPushNotify.Android</ApplicationId>
        <ApplicationVersion>1</ApplicationVersion>
        <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
        <AndroidPackageFormat>apk</AndroidPackageFormat>
        <AndroidEnableProfiledAot>False</AndroidEnableProfiledAot>
    </PropertyGroup>

    <ItemGroup>
        <None Remove="google-services.json" />
        <None Remove="Resources\drawable\ic_stat_ic_notification.png" />
    </ItemGroup>

    <ItemGroup>
        <AndroidResource Include="Icon.png">
            <Link>Resources\drawable\Icon.png</Link>
        </AndroidResource>
    </ItemGroup>

    <ItemGroup>
        <GoogleServicesJson Include="google-services.json" />
    </ItemGroup>

    <ItemGroup>
        <PackageReference Include="Avalonia.Android" Version="11.0.11" />
        <PackageReference Include="FirebaseAdmin" Version="3.0.0" />
        <PackageReference Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.9" />
        <PackageReference Include="Xamarin.Firebase.Core" Version="121.1.1.9" />
        <PackageReference Include="Xamarin.Firebase.Messaging" Version="124.0.0" />
        <PackageReference Include="Xamarin.Google.Dagger" Version="2.50.0" />
        <PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.4.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\AppUsingPushNotify\AppUsingPushNotify.csproj" />
    </ItemGroup>

    <ItemGroup>
        <None Update="appavaloniatestepushnotify-firebase-adminsdk-dz9zz-390c2557fc.json">
            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </None>
    </ItemGroup>
</Project>

I hope this helps anyone facing a similar issue.

Thank you for your assistance!