Xamarin android - 无法在单独的 Xamarin android 应用程序中启动服务

问题描述 投票:0回答:1

我创建了 2 个 Xamarin Android 应用程序。一个应用程序托管一个 Android 服务。另一个是客户端应用程序。假设仅调用 StartForegroundService 来启动服务。它不需要与服务通信或获取响应,因此不需要使用绑定的服务。

目前这只是 2 个测试应用程序。我在 Java 和 Android Studio 中创建了相同的应用程序。他们工作得很好。客户端在第二个应用程序中启动服务,没有问题。

Xamarin 口味不起作用。我 90% 确定问题出在 Xamarin Android 服务上,因为我的 Xamarin 客户端应用程序可以在 Java Android Studio 版本的服务中启动该服务。进一步测试还发现 Java android studio 客户端也无法启动 Xamarin android 服务。

因此,由于某种原因,当我在 Xamarin 中编写一个服务(尽可能相同)时,它无法由其他应用程序启动。但如果我用 Java 编写并使用 Android studio,它就可以正常工作。

这是我的服务应用程序的清单。

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.androidservicet3" android:installLocation="auto">
  <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="33" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  <uses-permission android:name="androidservicet3.AUTOSETTLE" />
  <permission android:name="androidservicet3.AUTOSETTLE" />
  <uses-permission android:name="android.permission.INTERNET" />
  <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" android:name="android.app.Application" android:debuggable="true" android:extractNativeLibs="true">
    <service android:exported="true" android:name="AndroidServiceT3.AutoSettleService" android:permission="androidservicet3.AUTOSETTLE">
      <intent-filter>
        <action android:name="androidservicet3.autosettle" />
      </intent-filter>
    </service>
    <activity android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar" android:name="crc645835191c6c6c2b11.MainActivity" android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <service android:name="crc64396a3fe5f8138e3f.KeepAliveService" />
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Battery Broadcast Receiver" android:name="crc64a0e0a82d0db9a07d.BatteryBroadcastReceiver" />
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Energy Saver Broadcast Receiver" android:name="crc64a0e0a82d0db9a07d.EnergySaverBroadcastReceiver" />
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Connectivity Broadcast Receiver" android:name="crc64a0e0a82d0db9a07d.ConnectivityBroadcastReceiver" />
    <activity android:configChanges="orientation|screenSize" android:name="crc64a0e0a82d0db9a07d.IntermediateActivity" />
    <provider android:authorities="com.companyname.androidservicet3.fileProvider" android:exported="false" android:grantUriPermissions="true" android:name="xamarin.essentials.fileProvider">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/xamarin_essentials_fileprovider_file_paths" />
    </provider>
    <activity android:configChanges="orientation|screenSize" android:name="crc64a0e0a82d0db9a07d.WebAuthenticatorIntermediateActivity" />
    <provider android:name="mono.MonoRuntimeProvider" android:exported="false" android:initOrder="1999999999" android:authorities="com.companyname.androidservicet3.mono.MonoRuntimeProvider.__mono_init__" />
  </application>
</manifest>

这是我客户的清单:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.settleclient" android:installLocation="auto">
  <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="33" />
  <uses-permission android:name="androidservicet3.AUTOSETTLE" />
  <uses-permission android:name="com.b2ps.servicetest2.autosettle" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  <uses-permission android:name="android.permission.INTERNET" />
  <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" android:name="android.app.Application" android:debuggable="true" android:extractNativeLibs="true">
    <activity android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar" android:name="crc641e54c039a041334a.MainActivity" android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <service android:name="crc64396a3fe5f8138e3f.KeepAliveService" />
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Battery Broadcast Receiver" android:name="crc64a0e0a82d0db9a07d.BatteryBroadcastReceiver" />
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Energy Saver Broadcast Receiver" android:name="crc64a0e0a82d0db9a07d.EnergySaverBroadcastReceiver" />
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Connectivity Broadcast Receiver" android:name="crc64a0e0a82d0db9a07d.ConnectivityBroadcastReceiver" />
    <activity android:configChanges="orientation|screenSize" android:name="crc64a0e0a82d0db9a07d.IntermediateActivity" />
    <provider android:authorities="com.companyname.settleclient.fileProvider" android:exported="false" android:grantUriPermissions="true" android:name="xamarin.essentials.fileProvider">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/xamarin_essentials_fileprovider_file_paths" />
    </provider>
    <activity android:configChanges="orientation|screenSize" android:name="crc64a0e0a82d0db9a07d.WebAuthenticatorIntermediateActivity" />
    <provider android:name="mono.MonoRuntimeProvider" android:exported="false" android:initOrder="1999999999" android:authorities="com.companyname.settleclient.mono.MonoRuntimeProvider.__mono_init__" />
  </application>
</manifest>

服务是这样的:

    [Service( Exported = true, Name = "AndroidServiceT3.AutoSettleService", Permission = "androidservicet3.AUTOSETTLE" )]
[IntentFilter( new String[] { "androidservicet3.autosettle" } )]
public class AutoSettleService : Android.App.Service
{
    private NotificationManager mNM;

    // Unique Identification Number for the Notification.
    // We use it on Notification start, and to cancel it.
    private int NOTIFICATION = Resource.String.autosettle_started;

    private System.Threading.Timer serviceRun = null;

    // This is the object that receives interactions from clients.  See
    // RemoteService for a more complete example.
    private IBinder mBinder;

    /**
     * Class for clients to access.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with
     * IPC.
     */
    public class LocalBinder : Android.OS.Binder
    {
        private AutoSettleService mService;

        public LocalBinder( AutoSettleService service ) { mService = service; }

        AutoSettleService GetService() { return mService; }
    }

    public override void OnCreate()
    {
        mBinder = new LocalBinder( this );
        mNM = ( NotificationManager )GetSystemService( Context.NotificationService );
        // mLogger = Logger.getDefault();

        // Display a notification about us starting.  We put an icon in the status bar.
        // ShowNotification();
    }

    public override void OnStart( Intent intent, int startId )
    {
        base.OnStart( intent, startId );
        Android.Util.Log.Debug( "AUTOSETTLESERVICE", "AUTOSETTLESERVICE: OnStart" );
    }

    public override StartCommandResult OnStartCommand( Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId )
    {
        Android.Util.Log.Debug( "AUTOSETTLESERVICE", "Received start id " + startId + ": " + intent );

        try
        {
            Intent notificationIntent = new Intent( this, typeof( MainActivity ) );
            notificationIntent.SetAction( AutoSettleConst.AUTOSETTLESERVICE_ACTION );
            PendingIntent pendingIntent = PendingIntent.GetActivity( this, 0, notificationIntent, PendingIntentFlags.Immutable );

            Notification notification = new Notification.Builder( this, AutoSettleConst.APP_CHANNEL_TXN_ID )
                    .SetContentTitle( "Auto-Settle" )
                    .SetContentText( "Running Auto-Settle" )
                    .SetSmallIcon( Resource.Drawable.AppLogo)
                    .SetContentIntent( pendingIntent )
                    .SetTicker( "ticker text" )
                    .SetOngoing( true )
                    .Build();
            // .SetForegroundServiceBehavior( ( int )NotificationForegroundService.Immediate )

            // Notification ID cannot be 0.
            StartForeground( AutoSettleConst.AUTOSETTLE_NOTIFICATION, notification );

            serviceRun = new System.Threading.Timer( ServiceTimer, null, 0, 1000 );
            // autoSettleTask = Task.Run( () => {
            //     Console.WriteLine( "Do auto settle" );
            //     AutoSettleTask();
            // } );
        }
        catch( Exception e )
        {
            Android.Util.Log.Debug( "AUTOSETTLESERVICE", e.ToString() );
        }
        return StartCommandResult.Sticky;
    }

    public override void OnDestroy()
    {
        // Cancel the persistent notification.
        mNM.Cancel( NOTIFICATION );

        // Tell the user we stopped.
        Android.Util.Log.Debug( "AUTOSETTLESERVICE", "Service destroyed" );
    }

    public override IBinder OnBind( Intent intent )
    {
        Android.Util.Log.Debug( "AUTOSETTLESERVICE", "AUTOSETTLESERVICE: binding" );
        return mBinder;
    }

    public override bool OnUnbind( Intent intent )
    {
        Android.Util.Log.Debug( "AUTOSETTLESERVICE", "AUTOSETTLESERVICE: unbinding" );
        return base.OnUnbind( intent );
    }

    private int _serviceCounter = 0;
    private void ServiceTimer( object state )
    {
        Android.Util.Log.Debug( "AUTOSETTLESERVICE", $"AUTOSETTLESERVICE: ServiceTimer: {_serviceCounter++}" );
        if( _serviceCounter >= 15 )
        {
            serviceRun.Dispose();
            serviceRun = null;
            this.StopSelf();
            Android.Util.Log.Debug( "AUTOSETTLESERVICE", $"AUTOSETTLESERVICE: Stopping service" );
        }
    }

    /**
     * Show a notification while this service is running.
     */
    private void ShowNotification()
    {
        // In this sample, we'll use the same text for the ticker and the expanded notification
        string text = GetText( Resource.String.autosettle_started );

        // The PendingIntent to launch our activity if the user selects this notification
        // PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
        //         new Intent(this, LocalServiceActivities.Controller.class), 0);
        Intent notificationIntent = new Intent( this, typeof( MainActivity ) );
        PendingIntent contentIntent = PendingIntent.GetActivity( this, 0, notificationIntent, PendingIntentFlags.Immutable );

        // Set the info for the views that show in the notification panel.
        Notification notification = new Notification.Builder( this )
                .SetSmallIcon( Resource.Drawable.AppLogo )  // the status icon
                .SetTicker( text )  // the status text
                                    // .SetWhen( System.currentTimeMillis() )  // the time stamp
                .SetContentTitle( GetText( Resource.String.autosettle_label ) )  // the label of the entry
                .SetContentText( text )  // the contents of the entry
                .SetContentIntent( contentIntent )  // The intent to send when the entry is clicked
                .Build();

        // Send the notification.
        mNM.Notify( NOTIFICATION, notification );
    }
}


public class AutoSettleConst
{

    public const string AUTOSETTLE_ACTION = "com.somecompany.terminalservice.autosettlets";
    public const string AUTOSETTLENOTIFY_ACTION = "com.somecompany.terminalservice.autosettlenotify";
    public const string AUTOSETTLESERVICE_ACTION = "com.somecompany.terminalservice.autosettleservice";
    public const string AUTOSETTLE_TIMEOUT_ACTION = "com.somecompany.terminalservice.autosettletimeout";


    // Android notification constants
    public const string APP_CHANNEL_TXN = "Transaction ChannelXX";
    public const string APP_CHANNEL_TXN_ID = "com.somecompany.terminalservice.txn";
    public const string APP_CHANNEL_TXN_DESCRIPTION = "Transaction notifications";

    public const int AUTOSETTLE_NOTIFICATION = 1001;

}
android xamarin service
1个回答
0
投票

您需要在客户端应用程序的清单中添加类似的内容,因为它面向 API30+:

<queries>
    <package android:name="com.companyname.androidservicet3" />
</queries>

然后您应该能够在其他应用程序中启动该服务:

var intent = new Intent();
intent.SetComponent(new ComponentName(
    "com.companyname.androidservicet3",
    "AndroidServiceT3.AutoSettleService"));
Application.Context.StartService(intent);
© www.soinside.com 2019 - 2024. All rights reserved.