기술 블로그

react-native android 14 정확한 알람 대응 본문

프론트엔드

react-native android 14 정확한 알람 대응

jaegwan 2024. 1. 13. 16:36
반응형

정확한 알람 예약은 기본적으로 거부됨

https://developer.android.com/about/versions/14/behavior-changes-all?hl=ko

안드로이드 14부터 정확한 알람 권한이 비활성화 되어 사용자로 부터 권한을 받아야 한다.

사내에서 운영 중인 어플리케이션은 rn 서드파티 라이브러리를 통해 권한을 요청하고 관리해왔지만

현 시점 대응한 라이브러리가 없어 직접 네이티브 모듈을 구축해야했다.

SCHEDULE_EXACT_ALARM은 선택적 권한이 아니기 때문에

알림상자로 권한 승인은 불가능하고 해당 앱의 설정으로 이동시켜주는것이 최선이다.

 

// android/app/src/main/AndroidManifest.xml

.
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
.
// android/app/src/main/java/com/integrateapp/AlarmPermissionModule.java


import android.app.AlarmManager;
import android.content.Context;
import android.os.Build;
import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;

public class AlarmPermissionModule extends ReactContextBaseJavaModule {

    public AlarmPermissionModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "AlarmPermissionModule";
    }
    // 알람을 묻습니다.
    @ReactMethod
    public void canScheduleExactAlarms(Promise promise) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            AlarmManager alarmManager = (AlarmManager) getReactApplicationContext().getSystemService(Context.ALARM_SERVICE);
            promise.resolve(alarmManager.canScheduleExactAlarms());
        } else {
            promise.resolve(true); // Older versions don't require this permission
        }
    }
     // 설정창으로 이동합니다.
    @ReactMethod
    public void openAlarmSettings() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
            intent.setData(Uri.parse("package:com.hackers.HackersOne"));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (intent.resolveActivity(getReactApplicationContext().getPackageManager()) != null) {
                getReactApplicationContext().startActivity(intent);
            }
        }
    }
}
// android/app/src/main/java/com/이름/AlarmPermissionModule.java

package com.hackers.integrateapp;

import android.app.AlarmManager;
import android.content.Context;
import android.os.Build;
import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;

public class AlarmPermissionModule extends ReactContextBaseJavaModule {

    public AlarmPermissionModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "AlarmPermissionModule";
    }
    // 알람을 묻습니다.
    @ReactMethod
    public void canScheduleExactAlarms(Promise promise) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            AlarmManager alarmManager = (AlarmManager) getReactApplicationContext().getSystemService(Context.ALARM_SERVICE);
            promise.resolve(alarmManager.canScheduleExactAlarms());
        } else {
            promise.resolve(true); // Older versions don't require this permission
        }
    }
     // 설정창으로 이동합니다.
    @ReactMethod
    public void openAlarmSettings() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
            intent.setData(Uri.parse("package:com.hackers.HackersOne"));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (intent.resolveActivity(getReactApplicationContext().getPackageManager()) != null) {
                getReactApplicationContext().startActivity(intent);
            }
        }
    }
}
packages.add(new AlarmPermissionPackage());
// permission.ts

import {Alert, Platform, NativeModules, Linking} from 'react-native';
import * as Permissions from 'react-native-permissions';
import COMMON_STATES from '../../../../Constants/Common';

const {AlarmPermissionModule} = NativeModules;


const permissionScheduleExactAlarm = async () => {
  if (Platform.OS === 'ios' || (Platform.Version as number) < 34) {
    return true;
  }

  try {
    // 권한 확인
    const scheduleExactAlarmPermission = await AlarmPermissionModule.canScheduleExactAlarms();
    console.log('permission ' + scheduleExactAlarmPermission);
    if (scheduleExactAlarmPermission) {
      return true;
    }
    return false;
  } catch (e) {
    throw new Error('permissionScheduleExactAlarm error');
  }
};
const ScheduleExactAlarmSetting = () => {
  AlarmPermissionModule.openAlarmSettings();
};

const addAlarmPermissionRequireAlert = () => {
  Alert.alert(
    '권한 등록',
    '앱을 사용하기 위해\n접근 권한 허용이 필요합니다.',
    [
      {text: '권한설정', onPress: ScheduleExactAlarmSetting},
      //
      {text: '취소'},
    ],
    {
      cancelable: false,
    },
  );
};


//노티 권한 ( POST_NOTIFICATIONS)
const permissionNotification = async () => {
  if (Platform.OS === 'ios' || (Platform.Version as number) < 33) {
    return true;
  }

  const PERMISSION =
    Platform.OS === 'android'
      ? Permissions.PERMISSIONS.ANDROID.POST_NOTIFICATIONS
      : Permissions.PERMISSIONS.IOS.CAMERA;

  try {
    const notificationPermission = await Permissions.request(PERMISSION);
    if (notificationPermission !== Permissions.RESULTS.GRANTED) {
      return false;
    }
    return true;
  } catch (e) {
    throw new Error('permissionNotification error');
  }
};

//노티 얼럿( POST_NOTIFICATIONS)
const addNotificationPermissionRequireAlert = () => {
  Alert.alert(
    '권한 등록',
    '앱을 사용하기 위해\n접근 권한 허용이 필요합니다.',
    [
      {
        text: '권한설정',
        onPress: () =>
          Linking.sendIntent('android.settings.APP_NOTIFICATION_SETTINGS', [
            {
              key: 'android.provider.extra.APP_PACKAGE',
              value: COMMON_STATES.androidPackageName,
            },
          ]),
      },
      //
      {text: '취소'},
    ],
    {
      cancelable: false,
    },
  );
};

export {
  permissionScheduleExactAlarm,
  addNotificationPermissionRequireAlert,
  permissionNotification,
  addAlarmPermissionRequireAlert,
};

 

 

사용

const isPermissionCamera = await permissionNotification();
    if (!isPermissionCamera) {
      addNotificationPermissionRequireAlert();
      return;
    }

 

 

AOS 13 이상 POST_NOTIFICATIONS 대응

위와 같은 이유로 해당 권한을 추가하는 부분도 구현되어 있다.
반응형

'프론트엔드' 카테고리의 다른 글

js 입출력  (0) 2023.11.16
[TIL] 에러코드  (0) 2023.10.20
[TIL] 웹 브라우저 이해  (0) 2023.10.17
[TIL] Docker GCP CI/CD  (0) 2023.10.15
[TIL] 모듈 번들러  (0) 2023.10.15
Comments