알림을 표시하지 않고 Foreground ()를 시작하는 방법은 무엇입니까?
서비스를 만들고 포 그라운드에서 실행하고 싶습니다.
대부분의 예제 코드에는 알림이 있습니다. 하지만 알림을 표시하고 싶지 않습니다. 가능합니까?
몇 가지 예를 들어 주시겠습니까? 대안이 있습니까?
내 앱 서비스가 미디어 플레이어를 수행하고 있습니다. 앱을 제외하고 시스템이 내 서비스를 죽이지 않게 만드는 방법 (예 : 버튼으로 음악 일시 중지 또는 중지).
안드로이드 플랫폼의 보안 기능으로, 당신은 할 수없는 , 아래에 어떤 상황도 통지를하지 않고 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 의 답변 에 대한 기술 구현은 다음과 같습니다 .
암호
ForegroundService.java
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;
}
}
ForegroundEnablingService.java
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;
}
}
AndroidManifest.xml
<service android:name=".ForegroundEnablingService" />
<service android:name=".ForegroundService" />
적합성
테스트 및 작업 :
- 공식 에뮬레이터
- 4.0.2
- 4.1.2
- 4.2.2
- 4.3.1
- 4.4.2
- 5.0.2
- 5.1.1
- 6.0
- 7.0
- Sony Xperia M
- 4.1.2
- 4.3
- 삼성 갤럭시 ?
- 4.4.2
- 5.X
- Genymotion
- 5.0
- 6.0
- CyanogenMod
- 5.1.1
Android 7.1에서 더 이상 작동하지 않습니다.
이것을 사용할 수 있습니다 (@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
.NET Framework 대신 지원 라이브러리 v7에서 제공 하는 것을 사용해야 Notification.Builder
합니다.
Notification 생성자에 대한 icon 매개 변수를 0으로 설정 한 다음 결과 알림을 startForeground ()에 전달했습니다. 로그에 오류가없고 알림이 표시되지 않습니다. 하지만 서비스가 성공적으로 포 그라운드되었는지 여부는 모르겠습니다. 확인할 방법이 있습니까?
편집 됨 : dumpsys로 확인했으며 실제로 서비스는 내 2.3 시스템에서 포 그라운드됩니다. 아직 다른 OS 버전으로 확인하지 않았습니다.
한 가지 해결 방법이 있습니다. 아이콘을 설정하지 않고 알림을 생성하면 알림이 표시되지 않습니다. 어떻게 작동하는지 모르지만 작동합니다. :)
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Title")
.setTicker("Title")
.setContentText("App running")
//.setSmallIcon(R.drawable.picture)
.build();
startForeground(101, notification);
버전 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 {
//...
}
}
}
}
And in 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);
}
}
A persistent notification is not shown, however you will see the Android 'x apps are running in the background' notification.
Block the foreground service notification
Android 7.1+ can't be exploited to hide the notification. Instead, get the user to block it.
Android 4.1 - 7.1
The only way is to block all notifications from your app:
Send user to app's details screen:
Uri uri = Uri.fromParts("package", getPackageName(), null); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri); startActivity(intent);
Have user block app's notifications
Note this also blocks your app's toasts.
Android 8
It's not worth blocking the notification on Android O because the OS will just replace it with a "running in the background" or "using battery" notification.
Android 9
Use a Notification Channel to block just the service notification.
- Assign service notification to notification channel
Send user to notification channel's settings
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()) .putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId()); startActivity(intent);
Have user block channel's notifications
You can hide notification on Android 9 by using custom layout with layout_height = "0dp"
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>
Tested on Pixel 1, android 9. This solution doesn't work on Android 8 or less
Here is a way to make your app 's oom_adj to 1 (Tested in ANDROID 6.0 SDK emulator). Add a temporary service, In your main service call startForgroundService(NOTIFICATION_ID, notificion)
. And then start the temporary service call startForgroundService(NOTIFICATION_ID, notificion)
with same notification id again, after a while in the temporary service call stopForgroundService(true) to dismiss the onging ontification.
You can also declare your application as persistent.
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@style/Theme"
*android:persistent="true"* >
</application>
This essentially sets your app at a higher memory priority, decreasing the probability of it being killed.
I developed a simple media player couple of months ago. So what I believe is if you are doing something like:
Intent i = new Intent(this, someServiceclass.class);
startService(i);
Then then system shouldn't be able to kill your service.
reference: read the paragraph which discuss when system stops the service
참고URL : https://stackoverflow.com/questions/10962418/how-to-startforeground-without-showing-notification
'programing tip' 카테고리의 다른 글
여러 값과 일치하는 if 문 (0) | 2020.10.31 |
---|---|
웹 페이지의 콘텐츠를 가져 와서 문자열 변수에 저장하는 방법 (0) | 2020.10.31 |
프로젝트의 / resources 폴더에있는 파일의 절대 경로를 얻는 방법 (0) | 2020.10.31 |
C-숫자가 소수인지 확인 (0) | 2020.10.31 |
배열을 IEnumerable로 캐스팅 (0) | 2020.10.30 |