서비스를 만들고 포 그라운드에서 실행하고 싶습니다.
대부분의 예제 코드에는 알림이 있습니다. 하지만 알림을 표시하고 싶지 않습니다. 가능합니까?
몇 가지 예를 들어 주시겠습니까? 대안이 있습니까?
내 앱 서비스가 미디어 플레이어를 수행하고 있습니다. 앱을 제외하고 시스템이 내 서비스를 죽이지 않게 만드는 방법 (예 : 버튼으로 음악 일시 중지 또는 중지).
서비스를 만들고 포 그라운드에서 실행하고 싶습니다.
대부분의 예제 코드에는 알림이 있습니다. 하지만 알림을 표시하고 싶지 않습니다. 가능합니까?
몇 가지 예를 들어 주시겠습니까? 대안이 있습니까?
내 앱 서비스가 미디어 플레이어를 수행하고 있습니다. 앱을 제외하고 시스템이 내 서비스를 죽이지 않게 만드는 방법 (예 : 버튼으로 음악 일시 중지 또는 중지).
답변:
안드로이드 플랫폼의 보안 기능으로, 당신은 할 수없는 , 아래에 어떤 상황도 통지를하지 않고 foregrounded 서비스가있다. 이는 포 그라운드 서비스가 더 많은 양의 리소스를 소비하고 백그라운드 서비스와 다른 스케줄링 제약 (즉, 빠르게 종료되지 않음)이 적용되고 사용자가 배터리를 먹는 원인을 알아야하기 때문입니다. 그러니 이러지 마세요 .
그러나, 그것은 이다 , 즉는 "가짜"알림을 가질 수 있습니다, 당신은 투명 알림 아이콘 (IIRC) 할 수 있습니다. 이것은 사용자에게 극도로 불명예하며 배터리를 죽여 악성 코드를 생성하는 것 외에는 할 이유가 없습니다.
업데이트 : 이것은 Android 7.1에서 "수정"되었습니다. https://code.google.com/p/android/issues/detail?id=213309
4.3 업데이트 이후, 그것은 기본적으로의 불가능 과 함께 서비스를 시작 startForeground()
알림을 표시하지 않고.
그러나 공식 API를 사용하여 아이콘을 숨길 수 있습니다. 투명 아이콘이 필요하지 않습니다. ( NotificationCompat
이전 버전을 지원하는 데 사용 )
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setPriority(Notification.PRIORITY_MIN);
알림 자체가 여전히 있어야한다는 사실에 화해했지만 여전히 알림을 숨기고 싶은 사람을 위해 해결 방법을 찾았을 수도 있습니다.
startForeground()
알림과 모든 것으로 가짜 서비스를 시작하십시오 .startForeground()
(동일한 알림 ID) 로 실행하려는 실제 서비스를 시작하십시오.stopSelf()
및 onDestroy call에서 호출 할 수 있음 stopForeground(true)
).Voilà! 알림이 전혀없고 두 번째 서비스가 계속 실행됩니다.
이는 Android 7.1에서 더 이상 작동하지 않으며 Google Play의 개발자 정책을 위반할 수 있습니다 .
Lior Iluz 의 답변 에 대한 기술 구현은 다음과 같습니다 .
public class ForegroundService extends Service {
static ForegroundService instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
if (startService(new Intent(this, ForegroundEnablingService.class)) == null)
throw new RuntimeException("Couldn't find " + ForegroundEnablingService.class.getSimpleName());
}
@Override
public void onDestroy() {
super.onDestroy();
instance = null;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
public class ForegroundEnablingService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (ForegroundService.instance == null)
throw new RuntimeException(ForegroundService.class.getSimpleName() + " not running");
//Set both services to foreground using the same notification id, resulting in just one notification
startForeground(ForegroundService.instance);
startForeground(this);
//Cancel this service's notification, resulting in zero notifications
stopForeground(true);
//Stop this service so we don't waste RAM.
//Must only be called *after* doing the work or the notification won't be hidden.
stopSelf();
return START_NOT_STICKY;
}
private static final int NOTIFICATION_ID = 10;
private static void startForeground(Service service) {
Notification notification = new Notification.Builder(service).getNotification();
service.startForeground(NOTIFICATION_ID, notification);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
<service android:name=".ForegroundEnablingService" />
<service android:name=".ForegroundService" />
테스트 및 작업 :
Android 7.1에서 더 이상 작동하지 않습니다.
ForegroundService
이것을 사용할 수 있습니다 (@Kristopher Micinski가 제안한대로) :
Notification note = new Notification( 0, null, System.currentTimeMillis() );
note.flags |= Notification.FLAG_NO_CLEAR;
startForeground( 42, note );
최신 정보:
Android KitKat + 릴리스에서는 더 이상 허용되지 않습니다. 그리고 이것은 @Kristopher Micinski가 언급 한대로 백그라운드 작업을 사용자에게 표시하는 Android의 디자인 원칙을 다소 위반한다는 점을 명심하십시오.
경고 :이 답변이 작동하는 것처럼 보이지만 실제로 는 서비스가 포 그라운드 서비스가되는 것을 조용히 방지합니다 .
원래 답변 :
알림 ID를 0으로 설정하기 만하면됩니다.
// field for notification ID
private static final int NOTIF_ID = 0;
...
startForeground(NOTIF_ID, mBuilder.build());
NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotificationManager.cancel(NOTIF_ID);
...
얻을 수있는 이점은 Service
높은 메모리 압력이없는 한 Android 시스템에 의해 파괴되지 않고 높은 우선 순위로 실행될 수 있다는 것입니다.
편집하다
Pre-Honeycomb 및 Android 4.4 이상에서 작동하도록하려면 NotificationCompat.Builder
지원 라이브러리 v7에서 제공하는 Notification.Builder
.
Notification.Builder
지원 라이브러리 v4 NotificationCompat.Builder
및 지원 라이브러리 v7을 시도했습니다 NotificationCompat.Builder
. 알림 창 또는 상태 표시 줄에 알림이 표시되지 않았지만 getRunningServices()
및 을 사용하여 확인했을 때 서비스가 포 그라운드 모드에서 실행되지 않았습니다 dumpsys
.
adb shell dumpsys activity services
확인에 사용 합니다.
layout_height = "0dp"인 맞춤 레이아웃을 사용하여 Android 9 이상에서 알림을 숨길 수 있습니다.
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.custom_notif);
builder.setContent(remoteViews);
builder.setPriority(NotificationCompat.PRIORITY_LOW);
builder.setVisibility(Notification.VISIBILITY_SECRET);
custom_notif.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp">
</LinearLayout>
Pixel 1, Android 9에서 테스트되었습니다.이 솔루션은 Android 8 이하에서 작동하지 않습니다.
업데이트 : 더 이상 Android 4.3 이상에서 작동하지 않습니다.
한 가지 해결 방법이 있습니다. 아이콘을 설정하지 않고 알림을 생성하면 알림이 표시되지 않습니다. 어떻게 작동하는지 모르지만 작동합니다. :)
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Title")
.setTicker("Title")
.setContentText("App running")
//.setSmallIcon(R.drawable.picture)
.build();
startForeground(101, notification);
(YourServiceName) is running
아이콘을 지정하지 않으면 자신 의 알림 대신 알림을 표시 합니다. CommonsWare에 따르면 Android 4.3 이후에 해당됩니다. commonsware.com/blog/2013/07/30/…
업데이트 : 더 이상 Android 4.3 이상에서 작동하지 않습니다.
Notification 생성자에 대한 icon 매개 변수를 0으로 설정 한 다음 결과 알림을 startForeground ()에 전달했습니다. 로그에 오류가없고 알림이 표시되지 않습니다. 하지만 서비스가 성공적으로 포 그라운드되었는지 여부는 모르겠습니다. 확인할 방법이 있습니까?
편집 됨 : dumpsys로 확인했으며 실제로 서비스는 내 2.3 시스템에서 포 그라운드됩니다. 아직 다른 OS 버전으로 확인하지 않았습니다.
Notification()
생성자를 호출하십시오 .
여기에서 대부분의 답변은 작동하지 않거나 포 그라운드 서비스가 중단 되거나 Google Play 정책을 위반 합니다.
안정적이고 안전하게 알림을 숨기는 유일한 방법은 사용자가 알림을 차단하도록하는 것입니다.
유일한 방법은 앱의 모든 알림 을 차단 하는 것입니다 .
사용자를 앱의 세부 정보 화면으로 보냅니다.
Uri uri = Uri.fromParts("package", getPackageName(), null);
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri);
startActivity(intent);
사용자가 앱의 알림을 차단하도록합니다.
이것은 또한 앱의 토스트를 차단합니다.
OS가 " 백그라운드에서 실행 중 "또는 " 배터리 사용 "알림으로 대체하기 때문에 Android O에서 알림을 차단할 가치가 없습니다 .
알림 채널 을 사용 하여 다른 알림에 영향을주지 않고 서비스 알림을 차단합니다.
사용자를 알림 채널 설정으로 보내기
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName())
.putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId());
startActivity(intent);
사용자 차단 채널 알림
버전 4.3 (18) 이상은 서비스 알림을 숨길 수 없지만 아이콘을 비활성화 할 수 있으며 버전 4.3 (18) 이하는 알림을 숨길 수 있습니다.
Notification noti = new Notification();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
noti.priority = Notification.PRIORITY_MIN;
}
startForeground(R.string.app_name, noti);
Android 8.0에서 알림 채널을 사용하지 않아도 여전히 가능하다는 것을 알았습니다.
public class BootCompletedIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent notificationIntent = new Intent(context, BluetoothService.class);
context.startForegroundService(notificationIntent);
} else {
//...
}
}
}
}
그리고 BluetoothService.class에서 :
@Override
public void onCreate(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent notificationIntent = new Intent(this, BluetoothService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification.Builder(this)
.setContentTitle("Title")
.setContentText("App is running")
.setSmallIcon(R.drawable.notif)
.setContentIntent(pendingIntent)
.setTicker("Title")
.setPriority(Notification.PRIORITY_DEFAULT)
.build();
startForeground(15, notification);
}
}
지속적인 알림은 표시되지 않지만 Android 'x 앱이 백그라운드에서 실행 중입니다'알림이 표시됩니다.
apps are running in the background
알림이 앱별 알림보다 더 나쁘다고 생각 하므로이 접근 방식이 그만한 가치가 있는지 모르겠습니다.
업데이트 : 더 이상 Android 7.1 이상에서 작동하지 않습니다.
다음은 앱의 oom_adj를 1로 만드는 방법입니다 (ANDROID 6.0 SDK 에뮬레이터에서 테스트 됨). 임시 서비스를 추가하십시오 startForgroundService(NOTIFICATION_ID, notificion)
. 그런 다음 startForgroundService(NOTIFICATION_ID, notificion)
동일한 알림 ID로 임시 서비스 호출 을 다시 시작하고 잠시 후 임시 서비스 호출 stopForgroundService (true)에서 ontification을 해제합니다.
애플리케이션을 지속적으로 선언 할 수도 있습니다.
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@style/Theme"
*android:persistent="true"* >
</application>
이것은 본질적으로 앱이 더 높은 메모리 우선 순위로 설정되어 앱이 종료 될 가능성을 줄입니다.
몇 달 전에 간단한 미디어 플레이어를 개발했습니다. 그래서 내가 믿는 것은 당신이 다음과 같은 것을하고 있다면 :
Intent i = new Intent(this, someServiceclass.class);
startService (i);
그러면 시스템이 서비스를 종료 할 수 없습니다.