반응형

안녕하세요

요즘 플로터를 공부중인데요 공부하면서 간단한 알림등록 및 알림기능이 있는 앱을 만들어 보았습니다.

 

소스는 무척이나 간단한데 제가 디자인에 대한 능력이 거의 제로에 가깝기 때문에 무척이나 투박한 앱인데요.

 

https://play.google.com/store/apps/details?id=com.yonggari.ddayreminder

 

D-Day 알리미 - Google Play 앱

D-Day 알리미는 중요한 날들을 잊지 않도록 도와주는 도구입니다.

play.google.com

 

 

 

먼가 궁금한점이 있다면 댓글달아주세요.

반응형
반응형

 제목 그래도 유니티 에디터에서는 광고가 보이는데 실제 안드로이드 기계에서는 광고가 안보일때 체크해봐야할 사항을 기억하기 위해 정리해봅니다.

 

물론 코드나 패키지에 문제가 없는 상황입니다.

 


Assets > External Dependency Manager > Android Resolver > Resolver

저 부분을 클릭합니다.

 

그 후

Project Settings > Player > Publishing Setting에서

Custom Proguard File을 체크합니다.

 

그럼 

Assets\Plugins\Android\Proguard-user.txt파일이 생성되는데

그 파일에

-keep class com.google.unity.** {

   *;

}

-keep public class com.google.android.gms.ads.**{

   public *;

}

-keep public class com.google.ads.**{

   public *;

}

-keepattributes *Annotation*

-dontobfuscate

 

위에 내용을 붙여넣습니다.

 

그럼 이제 광고가 잘 보일꺼에요

 

 

반응형
반응형

 Flutter의 로컬 Alert를 위한 flutter_local_notifications의 사용방법

 

이번에 일본어 공부를 위한 일본어 단어 공부 앱을 만들어 보았습니다.

일본어 단어 마스터 JLPT라는 앱인데

 

https://play.google.com/store/apps/details?id=com.yonggari.jlptmaster_kr

현재 심사 중인데 얼릉 통과됐으면 좋겠습니다.

 
이런 느낌으니 간단한 앱인데 언젠가는 이 앱에 대하여도 간단하게 소개하는 시간이 있을꺼 같습니다.
 
그런데 오늘은 앱에 대한 얘기보다 로컬알람에 대한 기록을 남기기 위에서 문서를 만들게 되었습니다.
 
워낙 간단해서 설명없이 쭉 나가겠습니다.
 
우선 플러그인을 설치해야겠죠
pubspec.yaml
의 dependencies:부분에
  flutter_local_notifications: ^17.2.4
  permission_handler: ^11.3.1
 
이렇게 설치합니다.
기존에 필요한건 
flutter_local_notifications
이거 하나만 있었어도 됐는데 
32버젼인가부터는 
permission_handler
로 퍼미션 컨트롤 하는 기능도 필요하게 되었습니다.
 
 
이제부터는 소스 간단하게 보시죠
우선 임포트하고요
 
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
 
tz의 타임존은 현재 나라마다의 시간을 구할려고 임포트 했습니다.
전 한국에서만 사용하는 앱이라서요.
 
void main() {
    ...
  _permissionWithNotification();
}
 
메인에서 퍼미션 관련 핸들링을 해줘야 합니다.
 
Future<void> requestNotificationPermissions() async {
  final PermissionStatus status = await Permission.notification.request();
  if (status.isGranted) {
    // Notification permissions granted
  } else if (status.isDenied) {
    // Notification permissions denied
    //await openAppSettings();
  } else if (status.isPermanentlyDenied) {
    // Notification permissions permanently denied, open app settings
    await openAppSettings();
  }
}

void _permissionWithNotification() async {
  if (await Permission.notification.isDenied &&
      !await Permission.notification.isPermanentlyDenied) {
    await [Permission.notification].request();
  }

  requestNotificationPermissions();

  //앱이 완전종료일 경우 푸시에서 데이터 받기설정
  final FlutterLocalNotificationsPlugin local =
      FlutterLocalNotificationsPlugin();
  NotificationAppLaunchDetails? details =
      await local.getNotificationAppLaunchDetails();
  if (details != null) {
    if (details.notificationResponse != null) {
      if (details.notificationResponse!.payload != null) {
        //
      }
    }
  }
}
 
요정도로 설정해주시면 될듯합니다.
위에 퍼미션을 체크해서 거부거나 등등의 상태일때도 다시 앱 기동시에
퍼미션을 요청하거나 수정할 수 있는데 저는 안받으면 그만인 그냥 권고의
푸시이므로 한번만 물어보고 거절하면 안보낼 생각입니다.
 
다음으로  runapp의 메인 클래스에서 초기화를 해줘야합니다.
 
메인앱입니다.() {
    _initializeNotifications();
  }

  void _initializeNotifications() async {
    tz.initializeTimeZones();
    final initializationSettingsAndroid =
        AndroidInitializationSettings('@mipmap/ic_launcher');
    final initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
    );
    await flutterLocalNotificationsPlugin.initialize(initializationSettings);
    _scheduleDailyNotification();
  }
 
 
void _scheduleDailyNotification() async {
    final notificationMessages = [
      "aaa",
      "bbb",
      "ccc",
      "ddd",
      "eee",
      "fff",
      "ggg",
      "hhh",
      "iii",
      "jjj"
    ];
    final random = Random();
    final selectedMessage =
        notificationMessages[random.nextInt(notificationMessages.length)];

    final scheduledTime = tz.TZDateTime(
      tz.getLocation('Asia/Seoul'),
      DateTime.now().year,
      DateTime.now().month,
      DateTime.now().day+1,
      12,
      00,
    );

    await flutterLocalNotificationsPlugin.zonedSchedule(
      0,
      '메세지 타이틀',
      selectedMessage,
      scheduledTime,
      const NotificationDetails(
        iOS: DarwinNotificationDetails(
          presentAlert: true,
          presentBadge: true,
          presentSound: true,
        ),
        android: AndroidNotificationDetails(
          '채널id',
          '채널name',
          importance: Importance.high,
          priority: Priority.high,
        ),
      ),
      uiLocalNotificationDateInterpretation:
          UILocalNotificationDateInterpretation.absoluteTime,
      matchDateTimeComponents: DateTimeComponents.time,
    );
  }
 
 
추가적으로 아이콘이나 등등의 추가 설정도 가능합니다만
전 간단하게 매일 낮 12시에 10개의 메세지 중에 1개를 선택하여 랜덤하게 발송 할 생각이므로 생략했습니다.
matchDateTimeComponents: DateTimeComponents.time,
이걸 설정해주면 매일 같은 시간에 메세지가 보내집니다.
 
워낙 간단한 소스라서 혹시 궁금한점 있으면 답글 달아주세요.
 
자 소스는 작성하였고 이제 권한 설정이 필요합니다.
 
sdk버젼마다 권한 설정이 다르고 보내는 메세지에 따라서도 권한 설정이 다르기 때문에 그부분은 공식문서를 참조하시는게 좋을듯 합니다.
참고로 저는 32 버젼으로 타케팅 되어있습니다.
 
android > app> src> main >AndroidManifest.xml에서
 
 
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" android:maxSdkVersion="32" />
    <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
.
.
.
.
.
 
 
        <receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
        <receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
            </intent-filter>
        </receiver>
    </application>
.
.
.
.
</manifest>
참고로 저는 권한을 좀 과하게 요청하였습니다.
큰화면이나 등등의 혹시 사용할지 몰라서 설정하였는데 필요없으신분은 빼셔도 괜찮습니다. 그런데 나중에도 잘되면 사용할 수 있겠다 싶어서..ㅎㅎㅎㅎ
 
이상 간단하게 설명 마쳤습니다.
 
궁금하신 내용은 댓글 달아주세요.



 

 

반응형
반응형

 Flutter 로 앱을 작성하면 android/app/build.gradle 파일이 targetSdkVersion를 관리해야 할 필요성이 생기게 됩니다.

 

현 시점에는 targetSdkVersion을 33으로 되어있으니 34로 업그레이드 해라라는 에러 메세지가 많이 발생합니다.

간단하게 하드코딩으로

targetSdkVersion 34로 문제없이 작동합니다.

 

지금까지는, 이것이 숫자가 하드 코드되어 있었다고 생각했지만, 문득 최근에 만든 프로젝트를 검토하면,

        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion

와 같이 설정되었습니다. 이것, 원래의 값은 어디에 있는 것일까?

 

Flutter SDK 3.13 이상 설정 소스

Flutter SDK 3.13부터는 < SDK install folder > /flutter/packages/flutter_tools/gradle/src/main/groovy 에 있는 flutter.groovy 파일로 변경되었다고 합니다.

 class FlutterExtension {

    /** Sets the compileSdkVersion used by default in Flutter app projects. */ 
    public final  int compileSdkVersion = 34

    /** Sets the minSdkVersion used by default in Flutter app projects. */ 
    public   final  int minSdkVersion = 21

    /** 
     * Sets the targetSdkVersion used by default in Flutter app projects. 
     *      targetSdkVersion      should always be the latest available stable version. 
.      */ 
    public final int targetSdkVersion = 34


Flutter SDK 2.8 이상 설정 소스

이것은, Flutter SDK 의 < SDK install folder > /flutter/packages/flutter_tools/gradle 에 있는 flutter.gradle 파일에 설정되어 있다고 합니다.

 /** For apps only. Provides the flutter extension used in app/build.gradle. */ 
class FlutterExtension {
     /** Sets the compileSdkVersion used by default in Flutter app projects. */ 
    static  int compileSdkVersion = 33

    /** Sets the minSdkVersion used by default in Flutter app projects. */ 
    static  int minSdkVersion = 16

    /** Sets the targetSdkVersion used by default in Flutter app projects. */ 
    static  int targetSdkVersion = 33



하드코딩으로 설정해도 무난하지만 좀 더 깊이 해당설정값이 어디에 있는지 궁금해서 찾아보고 기록으로 남겨놓게 되었습니다. 

 
참조가 되었으면 좋겠습니다.
반응형
반응형

구글 콘솔에서 앱 업로드시 버젼 코드가 기존과 같은 내용을 사용하여 발생하는 에러입니다.

 

두 곳의 내용을 수정하여야 합니다.

 

project > android > app > build.gradle

파일의 
 
if (flutterVersionCode == null) { flutterVersionCode = '1' <- 이 부분을 수정하고 }
 
 
없으면 아래 파일의 플러스 다음부분을 수정합니다.
 

 project > pubspec.yaml 

파일의
version: 0.0.1+1 <- 이 부분을 다르게 수정합니다.
 
이제 에러가 해결 되었습니다.
 
 
 
반응형
반응형

Flutter로 만든 앱을  구글 플레이 콘솔에 출시하기 위해서는 서명을 하고 빌드하여야만 파일을 업로드 할 수 있습니다.

 

아니면 이러한 메세지가 발생합니다.

디버그 모드로 서명한 APK 또는 Android App Bundle을 업로드했습니다. 출시 모드로 APK 또는 Android App Bundle에 서명해야 합니다

 

그 방법에 이야기해 보겠습니다.

 

 업로드 키 준비

빌드하기 전에 업로드 키를 만들고 서명할 준비를 합니다.※ 업로드 키로 서명하는 방법은 기존의 앱 서명 방법과 다르지 않습니다.

여기에서 서명한 내용이 처음 Play 스토어에 등록했을 때 업로드 키로 저장됩니다.

(1) 인증서 작성

jks파일을 만들고 만들기

터미널이나 커맨트 창에

keytool -genkey -v -keystore release.jks -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

위가 같이 입력합니다.

입력하라는 내용이 나오는데 적당히 입력해줍니다.

패스워드는 반듯이 기억하고 어딘가에 기록해둡니다.

만든 release.jks다음 android/app아래에 놓습니다

2) 서명 정보 파일 작성

 

android폴더아래에 keystore.properties 파일을만듭니다.

keystore.properties
 

 

storePassword=비밀번호
keyPassword=비밀번호
keyAlias=alias_name
storeFile=release.jks

 

(3) build.gradle 편집

app/build.gradle <- 이 파일입니다.
app/build.gradle
 
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

// 추가
def keystorePropertiesFile = rootProject.file("keystore.properties") 

android{
   ...

    defaultConfig {
        ...
    }

    // 이하를 추가
    signingConfigs {
        release {
            if (keystorePropertiesFile.exists()) {
                def keystoreProperties = new Properties()
                keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
                keyAlias keystoreProperties['keyAlias']
                keyPassword keystoreProperties['keyPassword']
                storeFile file(keystoreProperties['storeFile'])
                storePassword keystoreProperties['storePassword']
            }
        }
    }
    // 추가는 여기까지

    buildTypes {
        debug {
            ...
        }
        release {
            resValue "string", "app_name", "앱이름"

            // 다음 라인을 추가 혹시 디버그가 있으면 대체합니다.
            signingConfig signingConfigs.release
        }
    }
 ...
}
 
이제 빌드를 다시하여 생성된 파일을 업로드 하면 정상적으로 업로드 가능합니다.
반응형

+ Recent posts