13

携帯電話を8.1 Developer Previewにアップグレードすると、バックグラウンドサービスが正しく起動しなくなりました。Android 8.1へのアップグレード後にstartForegroundが失敗する

長年実行しているサービスでは、作成時に呼び出される進行中の通知を開始するstartForegroundメソッドを実装しました。

@TargetApi(Build.VERSION_CODES.O) 
private fun startForeground() { 
    // Safe call, handled by compat lib. 
    val notificationBuilder = NotificationCompat.Builder(this, DEFAULT_CHANNEL_ID) 

    val notification = notificationBuilder.setOngoing(true) 
      .setSmallIcon(R.drawable.ic_launcher_foreground) 
      .build() 
    startForeground(101, notification) 
} 

エラーメッセージ:サービス通知ため

11-28 11:47:53.349 24704-24704/$PACKAGE_NAMEE/AndroidRuntime: FATAL EXCEPTION: main 
    Process: $PACKAGE_NAME, PID: 24704 
    android.app.RemoteServiceException: Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: Notification(channel=My channel pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x42 color=0x00000000 vis=PRIVATE) 
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1768) 
     at android.os.Handler.dispatchMessage(Handler.java:106) 
     at android.os.Looper.loop(Looper.java:164) 
     at android.app.ActivityThread.main(ActivityThread.java:6494) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 

無効チャンネル、どうやら私の古いチャネルDEFAULT_CHANNEL_IDはもはや私が仮定API 27に対して適切ではありません。適切なチャンネルは何でしょうか?私は文書を見ようとしました

答えて

18

別の解決策でいくつか修正した後、8.1であなた自身の通知チャネルを作成する必要があるようです。

private fun startForeground() { 
    val channelId = 
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 
       createNotificationChannel() 
      } else { 
       // If earlier version channel ID is not used 
       // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) 
       "" 
      } 

    val notificationBuilder = NotificationCompat.Builder(this, channelId) 
    val notification = notificationBuilder.setOngoing(true) 
      .setSmallIcon(R.mipmap.ic_launcher) 
      .setPriority(PRIORITY_MIN) 
      .setCategory(Notification.CATEGORY_SERVICE) 
      .build() 
    startForeground(101, notification) 
} 


@RequiresApi(Build.VERSION_CODES.O) 
private fun createNotificationChannel(): String{ 
    val channelId = "my_service" 
    val channelName = "My Background Service" 
    val chan = NotificationChannel(channelId, 
      channelName, NotificationManager.IMPORTANCE_NONE) 
    chan.lightColor = Color.BLUE 
    chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE 
    val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 
    service.createNotificationChannel(chan) 
    return channelId 
} 

私の理解から、バックグラウンドサービスは、通知チャネルの選択を解除して表示しないことを選択できる通常の通知として表示されるようになりました。

更新:追加さKotlinタグ

+0

誰が 'val'ですか?... –

+2

これはKotlinコードです。 https://kotlinlang.orgをチェックしてください。これは、急速に成長しています偉大な小さな言語です! –

+0

@ ban-geoengineering他のコメントで述べたように。それは、Androidの正式にサポートされている言語の1つであるKotlinです。 – Rawa

6

がAndorid 8.1で正常に動作する:(任意の非推奨コードなし)

更新試料オレオ

更新よりも前のバージョンをサポートして更新溶液:

public NotificationBattery(Context context) { 
    this.mCtx = context; 

    mBuilder = new NotificationCompat.Builder(context, CHANNEL_ID) 
      .setContentTitle(context.getString(R.string.notification_title_battery)) 
      .setSmallIcon(R.drawable.ic_launcher) 
      .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) 
      .setChannelId(CHANNEL_ID) 
      .setOnlyAlertOnce(true) 
      .setPriority(NotificationCompat.PRIORITY_MAX) 
      .setWhen(System.currentTimeMillis() + 500) 
      .setGroup(GROUP) 
      .setOngoing(true); 

    mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_view_battery); 

    initBatteryNotificationIntent(); 

    mBuilder.setContent(mRemoteViews); 

    mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 

    if (AesPrefs.getBooleanRes(R.string.SHOW_BATTERY_NOTIFICATION, true)) { 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 
      NotificationChannel channel = new NotificationChannel(CHANNEL_ID, context.getString(R.string.notification_title_battery), 
        NotificationManager.IMPORTANCE_DEFAULT); 
      channel.setShowBadge(false); 
      channel.setSound(null, null); 
      mNotificationManager.createNotificationChannel(channel); 
     } 
    } else { 
     mNotificationManager.cancel(Const.NOTIFICATION_CLIPBOARD); 
    } 
} 

古いスニペ

public static final String NOTIFICATION_CHANNEL_ID_SERVICE = "com.mypackage.service"; 
public static final String NOTIFICATION_CHANNEL_ID_TASK = "com.mypackage.download_info"; 

public void initChannel(){ 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 
     NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
     nm.createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID_SERVICE, "App Service", NotificationManager.IMPORTANCE_DEFAULT)); 
     nm.createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID_INFO, "Download Info", NotificationManager.IMPORTANCE_DEFAULT)); 
    } 
} 

最高:私の場合は

@Override 
public int onStartCommand(Intent intent, int flags, final int startId) { 
    Log.d(TAG, "onStartCommand"); 

    String CHANNEL_ONE_ID = "com.kjtech.app.N1"; 
    String CHANNEL_ONE_NAME = "Channel One"; 
    NotificationChannel notificationChannel = null; 
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 
     notificationChannel = new NotificationChannel(CHANNEL_ONE_ID, 
       CHANNEL_ONE_NAME, IMPORTANCE_HIGH); 
     notificationChannel.enableLights(true); 
     notificationChannel.setLightColor(Color.RED); 
     notificationChannel.setShowBadge(true); 
     notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); 
     NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
     manager.createNotificationChannel(notificationChannel); 
    } 

    Bitmap icon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); 
    Notification notification = new Notification.Builder(getApplicationContext()) 
      .setChannelId(CHANNEL_ONE_ID) 
      .setContentTitle(getString(R.string.obd_service_notification_title)) 
      .setContentText(getString(R.string.service_notification_content)) 
      .setSmallIcon(R.mipmap.ic_launcher) 
      .setLargeIcon(icon) 
      .build(); 

    Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class); 
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 
    notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0); 

    startForeground(START_FOREGROUND_ID, notification); 

    return START_STICKY; 
} 
+1

上記のコードの一部が廃止されました。これはNotification.Builder(getApplicationContext())。setChannelId(CHANNEL_ONE_ID)... 'をNotification.Builder(getApplicationContext()、CHANNEL_ONE_ID)に変更することで解決できます。 .. ' –

+1

@ ban-geoengineeringあなたは絶対に正しいです...私は新しいサンプルコードを追加しました。ありがとう。 –

0

我々はNotificationChannelを指定せずに通知を投稿しようとしたので、それはです: - D(ない上記のコードに関連したそれは別のアプリがあります)私たちはすべてのために一度にそれを宣言する必要があるように、コードの上に置く場所は、ApplicationクラスのonCreate()方法である:

public class App extends Application { 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     initChannel(); 
    } 
} 

我々はこれを設定した後、我々は我々だけで、指定channelIdで通知を使用することができます:あなたはそれを使用したい場合は

int notifId = 45; 
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
nm.notify(notifId, builder.build()); 

Intent i = new Intent(this, MainActivity.class); 
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 
PendingIntent pi = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT); 
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID_INFO); 
      .setContentIntent(pi) 
      .setWhen(System.currentTimeMillis()) 
      .setContentTitle("VirtualBox.exe") 
      .setContentText("Download completed") 
      .setSmallIcon(R.mipmap.ic_launcher); 

をその後、我々は、通知を掲示するためにそれを使用することができますが前景サービスの通知として:

startForeground(notifId, builder.build()); 
関連する問題