@implementation ViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
    
}
 
// 쓰기
- (IBAction)onWriteFile:(UIButton *)sender {
    // 파일경로 - 앱샌드박스/Documents/test.txt
    NSString *directory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, TRUE) firstObject];
    NSString *filePath = [directory stringByAppendingPathComponent:@"test.txt"];
    
    // 텍스트
    NSString *text = [self.tfText.text stringByAppendingString:@"\n"];
    
    // 기존파일이 있는지 확인
    BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
    // 기존파일이 없으면 새로생성하여 파일쓰기
    if(!isExist) {
        NSError *error;
        [text writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
        if(error) {
            NSLog(@"File Write Error :%@ ", error.localizedDescription);
        }
    }
    // 기존파일이 있으면 파일핸들러로 파일끝으로 이동하여 파일쓰기
    else {
        NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
        if(fileHandle) {
            // 끝으로 이동
            [fileHandle seekToEndOfFile];
            // NSData로 바꾼후 파일쓰기
            NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
            [fileHandle writeData:data];
            [fileHandle closeFile];
        }
    }
}
 
// 읽기
- (IBAction)onReadFile:(UIButton *)sender {
    // 파일경로 - 앱샌드박스/Documents/test.txt
    NSString *directory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, TRUE) firstObject];
    NSString *filePath = [directory stringByAppendingPathComponent:@"test.txt"];
    
    // 파일읽기
    NSString *text = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    if(text) {
        [self.lbText setText:text];
    }
}
 
@end
 
cs

'IT > Ⅰ. IOS' 카테고리의 다른 글

[IOS] GPS 현재 위치 가져오기  (0) 2025.07.07
[IOS] TTS 사용  (3) 2025.07.06
[IOS] FCM Crashlytics 로그  (2) 2025.07.06
[IOS] FCM 발송  (0) 2025.06.30
[IOS] GIF, SVG, APNG 이미지 사용  (0) 2025.05.22
public class MainActivity extends AppCompatActivity {
 
    EditText editText;
    TextView text;
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        editText = findViewById(R.id.editText);
        text = findViewById(R.id.text);
 
        Button btnWrite = findViewById(R.id.btnWrite);
        btnWrite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                writeFile();
            }
        });
 
        Button btnRead = findViewById(R.id.btnRead);
        btnRead.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                readFile();
            }
        });
    }
 
    // 파일에 쓰기
    public void writeFile() {
        String text = editText.getText().toString() + "\n";
        // 위치 - /data/data/패키지명/files/test.txt
        File file = new File(getFilesDir(), "test.txt");
        // true - 기존 파일에 이어서 쓰기
        try (FileOutputStream fos = new FileOutputStream(file, true)) {
            fos.write(text.getBytes("UTF-8"));
            fos.flush();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    // 파일에서 읽기
    public void readFile() {
        // 위치 - /data/data/패키지명/files/test.txt
        File file = new File(getFilesDir(), "test.txt");
        try (   FileInputStream fis = new FileInputStream(file);
                InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
                BufferedReader br = new BufferedReader(isr); ) {
            // BufferedReader 를 사용하여 한줄씩 읽기
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line).append("\n");
            }
            fis.close();
 
            text.setText(sb.toString());
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
cs

 

  • 내부 저장소에 읽기/쓰기 할때는 따로 권한이 필요하지 않음

 

'IT > Ⅱ. Android' 카테고리의 다른 글

[Android] GPS 현재 위치 가져오기  (1) 2025.07.07
[Android] TTS 사용  (0) 2025.07.06
[Android] FCM Crashlytics 로그  (0) 2025.07.06
[Android] FCM 발송  (1) 2025.06.29
[Android] GIF, SVG, APNG 이미지 사용  (2) 2025.05.21
 

위치 권한 선언

 
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
 
 
@interface ViewController : UIViewController<CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) IBOutlet UILabel *txtGps;
 
 
@end
 
cs

 

 

#import "ViewController.h"
 
@interface ViewController ()
 
@end
 
@implementation ViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
    self.locationManager = [[CLLocationManager allocinit];
    self.locationManager.delegate = self;
    // 위치 정확도 설정
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    
    CLAuthorizationStatus status = self.locationManager.authorizationStatus;
    if (status == kCLAuthorizationStatusNotDetermined) {
        // 권한요청
        [self.locationManager requestWhenInUseAuthorization];
    }
    else if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {
        // 위치 업데이트 시작
        [self.locationManager startUpdatingLocation];
    }
    else {
        NSLog(@"위치 권한 거부");
    }
}
 
// 위치 권한 받음
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
    CLAuthorizationStatus status = manager.authorizationStatus;
    if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {
        // 위치 업데이트 시작
        [self.locationManager startUpdatingLocation];
    }
}
 
// 위치 업데이트
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    CLLocation *location = locations.lastObject;
    if(location) {
        double latitude = location.coordinate.latitude;
        double longitude = location.coordinate.longitude;
        [self.txtGps setText:[NSString stringWithFormat:@"위도 : %f , 경도 : %f", latitude, longitude]];
    }
}
 
// 위치 업데이트 - 실패
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    [self.txtGps setText:@""];
}
 
 
@end
 
cs

 

 

결과

'IT > Ⅰ. IOS' 카테고리의 다른 글

[IOS] 파일 읽기, 쓰기  (0) 2025.07.09
[IOS] TTS 사용  (3) 2025.07.06
[IOS] FCM Crashlytics 로그  (2) 2025.07.06
[IOS] FCM 발송  (0) 2025.06.30
[IOS] GIF, SVG, APNG 이미지 사용  (0) 2025.05.22
public class MainActivity extends AppCompatActivity {
 
    private final ActivityResultLauncher<String[]> permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
        @Override
        public void onActivityResult(Map<String, Boolean> o) {
            Boolean isFineLocation = o.get(Manifest.permission.ACCESS_FINE_LOCATION);
            Boolean isCoarseLocation = o.get(Manifest.permission.ACCESS_COARSE_LOCATION);
            if(isFineLocation == Boolean.TRUE || isCoarseLocation == Boolean.TRUE) {
                getCurrentLocation();
            }
        }
    });
 
    TextView txtGps;
 
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        txtGps = findViewById(R.id.txtGps);
 
        requestPermission();
    }
 
    // 위치 권한요청
    public void requestPermission() {
        if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            permissionLauncher.launch(new String[]{
                    Manifest.permission.ACCESS_FINE_LOCATION ,
                    Manifest.permission.ACCESS_COARSE_LOCATION
            });
            return;
        }
 
        getCurrentLocation();
    }
 
    // 현재 위치 가져오기
    public void getCurrentLocation() {
        if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
 
        FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(this);
        client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, null).addOnCompleteListener(thisnew OnCompleteListener<Location>() {
            @Override
            public void onComplete(@NonNull Task<Location> task) {
                if (task.isSuccessful()) {
                    txtGps.setText("위도 : " + task.getResult().getLatitude() + " , 경도 : " + task.getResult().getLongitude());
                }
                else {
                    txtGps.setText("");
                }
            }
        });
    }
}
 
cs

 

 

결과

'IT > Ⅱ. Android' 카테고리의 다른 글

[Android] 파일 읽기, 쓰기  (1) 2025.07.08
[Android] TTS 사용  (0) 2025.07.06
[Android] FCM Crashlytics 로그  (0) 2025.07.06
[Android] FCM 발송  (1) 2025.06.29
[Android] GIF, SVG, APNG 이미지 사용  (2) 2025.05.21

고품질(프리미엄) 음성 다운로드

설정 > 손쉬운 사용 > 말하기 > 실시간 말하기 - 켬 > 음성 > 고품질, 프리미엄 음성 다운로드

 

한글 - 프리미엄 음성 다운로드
영어 - 고품질 음성 다운로드

 

 

 

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
 
@implementation ViewController
{
    AVSpeechSynthesizer *synthesizer;
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 음성출력 객체
    synthesizer = [[AVSpeechSynthesizer allocinit];
}
 
- (void)viewWillDisappear:(BOOL)animated {
    // 출력중지
    if(synthesizer.isSpeaking) {
        [self->synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
    }
}
 
- (IBAction)onTTS:(UIButton *)sender {
    // 기존 출력멈추고 다시 실행
    if(synthesizer.isSpeaking) {
        [self->synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
    }
    
    // 말할문장 객체
    AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:@"안녕하세요!"];
    // 한국어설정
    utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"ko-KR"];
    // 음성속도 - 기본
    utterance.rate = AVSpeechUtteranceDefaultSpeechRate;
    // TTS
    [synthesizer speakUtterance:utterance];
}
 
@end
 
cs

'IT > Ⅰ. IOS' 카테고리의 다른 글

[IOS] 파일 읽기, 쓰기  (0) 2025.07.09
[IOS] GPS 현재 위치 가져오기  (0) 2025.07.07
[IOS] FCM Crashlytics 로그  (2) 2025.07.06
[IOS] FCM 발송  (0) 2025.06.30
[IOS] GIF, SVG, APNG 이미지 사용  (0) 2025.05.22

TTS : 텍스트를 음성으로 변환하는 Android 라이브러리 사용

 

 

public class MainActivity extends AppCompatActivity {
 
 
    TextToSpeech tts;
 
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        // Text To Speech 초기화
        tts = new TextToSpeech(thisnew TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                // TTS 초기화 완료
                if(status == TextToSpeech.SUCCESS) {
                    // 사용할 언어지정
                    tts.setLanguage(Locale.KOREAN);
                }
            }
        });
 
        Button btnTts = findViewById(R.id.btnTts);
        btnTts.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // TextToSpeech.QUEUE_FLUSH : 대기중인것을 모두 취소하고 즉시 TTS 실행
                tts.speak("안녕하세요!", TextToSpeech.QUEUE_FLUSH, nullnull);
            }
        });
    }
 
    @Override
    protected void onDestroy() {
        if(tts != null) {
            // 대기중이거나 실행중인 TTS 모두 중지
            tts.stop();
            // TTS 엔진 종료
            tts.shutdown();
        }
 
        super.onDestroy();
    }
}
 
cs

 

'IT > Ⅱ. Android' 카테고리의 다른 글

[Android] 파일 읽기, 쓰기  (1) 2025.07.08
[Android] GPS 현재 위치 가져오기  (1) 2025.07.07
[Android] FCM Crashlytics 로그  (0) 2025.07.06
[Android] FCM 발송  (1) 2025.06.29
[Android] GIF, SVG, APNG 이미지 사용  (2) 2025.05.21

dSYM 파일 자동 업로드

https://firebase.google.com/docs/crashlytics/get-started?hl=ko&platform=ios

 

Firebase Crashlytics 시작하기

새로운 Firebase Studio 기능부터 AI 통합 방법까지 I/O에서 발표된 모든 내용을 확인해 보세요. 블로그 읽기 의견 보내기 Firebase Crashlytics 시작하기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로

firebase.google.com

 

 

 

 

ViewController.m

@import FirebaseCore;
@import FirebaseCrashlytics;
 
 
- (IBAction)onCrashClick:(UIButton *)sender {
    @try {
        NSArray *arr = [[NSArray allocinit];
        NSString * a = arr[1];
    }
    @catch (NSException *exception) {
        NSError *error = [NSError errorWithDomain:@"com.blog.logging" code:1000 userInfo:@{
            NSLocalizedDescriptionKey : exception.reason ?: @"Unknown Exception" ,
            @"name" : exception.name ,
            @"description" : exception.description ?: @""
        }];
        [[FIRCrashlytics crashlytics] log:@"TEST Crash 발생!"];
        [[FIRCrashlytics crashlytics] setCustomValue:@(120) forKey:@"price"];
        [[FIRCrashlytics crashlytics] setCustomValue:@"iPhone16" forKey:@"model"];
        [[FIRCrashlytics crashlytics] setUserID:@"User02"];
        [[FIRCrashlytics crashlytics] recordError:error];
    }
}
 
cs

 

 

결과

Exception Stack Trace

 

커스텀키

 

커스텀 로그

 

사용자 ID 확인

 

'IT > Ⅰ. IOS' 카테고리의 다른 글

[IOS] GPS 현재 위치 가져오기  (0) 2025.07.07
[IOS] TTS 사용  (3) 2025.07.06
[IOS] FCM 발송  (0) 2025.06.30
[IOS] GIF, SVG, APNG 이미지 사용  (0) 2025.05.22
[IOS] 이미지로 프로그레스바 만들기  (0) 2025.05.17

build.gradle.kts (:app)

plugins {
    ...
    // 파이어베이스
    id("com.google.gms.google-services")
    id("com.google.firebase.crashlytics")
}
 
dependencies {
    ...
    // 파이어베이스
    implementation(platform("com.google.firebase:firebase-bom:33.15.0"))
    implementation("com.google.firebase:firebase-analytics")
    implementation("com.google.firebase:firebase-crashlytics")
}
cs

 

 

build.gradle.kts (:루트)

plugins {
    ...
    // 파이어베이스
    id("com.google.gms.google-services") version "4.4.3" apply false
    id("com.google.firebase.crashlytics") version "3.0.4" apply false
}
cs

 

 

proguard-rules.pro

-keepattributes SourceFile,LineNumberTable        # Keep file names and line numbers.
-keep public class * extends java.lang.Exception  # Optional: Keep custom exceptions.
cs

 

 

MainActivity.java

public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        Button btnTest = findViewById(R.id.btnTest);
        btnTest.setOnClickListener(view -> {
            try {
                int a = 1/0;
            }
            catch (Exception e) {
                FirebaseCrashlytics crash = FirebaseCrashlytics.getInstance();
                crash.log("TEST Crash 발생!");
                crash.setCustomKey("name""홍길동");
                crash.setCustomKey("address""서울특별시");
                crash.setCustomKey("phone""+821012341234");
                crash.setUserId("User01");
                crash.recordException(e);
            }
        });
    }
}
 
cs

 

 

결과

Exception Stack Trace

 

커스텀키

 

커스텀 로그

 

사용자 ID 확인

 

'IT > Ⅱ. Android' 카테고리의 다른 글

[Android] GPS 현재 위치 가져오기  (1) 2025.07.07
[Android] TTS 사용  (0) 2025.07.06
[Android] FCM 발송  (1) 2025.06.29
[Android] GIF, SVG, APNG 이미지 사용  (2) 2025.05.21
[Android] 이미지로 프로그레스바 만들기  (1) 2025.05.16

Android

https://ghj1001020.tistory.com/818

 

[Android] FCM 발송

google-services.json 파일을 다운받아서 프로젝트에 넣어준다 build.gradle.ktsplugins { ... // 파이어베이스 id("com.google.gms.google-services") version "4.4.2"} dependencies { ... // 파이어베이스 implementation(platform("com.goog

ghj1001020.tistory.com

IOS

https://ghj1001020.tistory.com/819

 

[IOS] FCM 발송

Key 발급Apple Developer Member Centerhttps://developer.apple.com/account/resources/authkeys/list 로그인 - Apple idmsa.apple.com APN 인증키 업로드 GoogleService-Info.plist 파일을 다운받아서 프로젝트에 넣어준다 AppDelegate@import

ghj1001020.tistory.com

 

 

service-account.json 파일을 다운받아서 프로젝트에 넣어준다

새 비공개 키 생성 클릭

 

 

 

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<project>
    ...
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.google.auth</groupId>
                <artifactId>google-auth-library-bom</artifactId>
                <version>1.30.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            
            <dependency>
                <groupId>com.fasterxml.jackson</groupId>
                <artifactId>jackson-bom</artifactId>
                <version>2.12.4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    
    </dependencyManagement>
 
 
    <dependencies>
        
        <dependency>
            <groupId>com.google.auth</groupId>
            <artifactId>google-auth-library-oauth2-http</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
        </dependency>
 
    </dependencies>
    
    ...
</project>
cs

 - 구글 인증 라이브러리와 json 처리 라이브러리 포함

 

 

Push.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
public class Push {
    
    private final String PROJECT_ID = "...";
    
    private final String FCM_URL = "https://fcm.googleapis.com/v1/projects/" + PROJECT_ID + "/messages:send";
    private final String[] SCOPES = {"https://www.googleapis.com/auth/firebase.messaging"};
    
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    
    // 발송
    public void send(String token, String title, String message) {
        try {
            HttpsURLConnection conn = getHttpsConnection(FCM_URL);
            conn.setConnectTimeout(60*1000);
            conn.setReadTimeout(60*1000);
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            
            // 헤더
            conn.setRequestProperty("Authorization""Bearer " + getAccessToken());
            conn.setRequestProperty("Content-Type""application/json; charset=UTF-8");
            
            // 푸시데이터
            PushData pushData = new PushData(token, title, message);
            // 푸시데이터 객체 -> JSON
            String jsonData = objectMapper.writeValueAsString(pushData);
            System.out.println("DATA : " + jsonData);
            
            conn.connect();
 
            // 데이터전송
            OutputStream os = conn.getOutputStream();
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
            bw.write(jsonData);
            bw.flush();
            
            // 응답
            int statusCode = conn.getResponseCode();
            try ( InputStream is = (statusCode == HttpURLConnection.HTTP_OK ? conn.getInputStream() : conn.getErrorStream());
                    BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")) ) {
                StringBuilder sb = new StringBuilder();
                String line;
                while((line = br.readLine()) != null) {
                    sb.append(line);
                }
                System.out.println(sb.toString());
            }
            
            conn.disconnect();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private HttpsURLConnection getHttpsConnection(String strUrl) throws IOException, NoSuchAlgorithmException, KeyManagementException {
        URL url = new URL(strUrl);
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
 
        conn.setHostnameVerifier(hostnameVerifier);
        
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManager, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        
        return conn;
    }
    
    // 사용자 인증 정보를 사용하여 액세스 토큰 발급
    private String getAccessToken() throws IOException {
        InputStream is = getClass().getClassLoader().getResourceAsStream("service-account.json");
        GoogleCredentials googleCredentials = GoogleCredentials.fromStream(is)
                .createScoped(Arrays.asList(SCOPES));
        googleCredentials.refresh();
        return googleCredentials.getAccessToken().getTokenValue();
    }
    
    HostnameVerifier hostnameVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String arg0, SSLSession arg1) {
            // 항상허용
            return true;
        }
    };
    
    TrustManager[] trustManager = new TrustManager[] {
            new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                }
 
                @Override
                public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                }
 
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[] {};
                }
            }
    };
}
 
cs

 - 푸시 발송 클래스

 

 

PushData.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class PushData {
    
    Message message;
    
    public PushData(String token, String title, String content) {
        this.message = new Message();
        this.message.token = token;
        this.message.data = new Data();
        this.message.data.title = title;
        this.message.data.content = content;
        this.message.notification = new Notification();
        this.message.notification.title = title;
        this.message.notification.body = content;
    }
    
    public Message getMessage() {
        return message;
    }
 
    public void setMessage(Message message) {
        this.message = message;
    }
 
 
 
    public static class Message {
        String token;
        Data data;
        Notification notification;
        
        public String getToken() {
            return token;
        }
        public void setToken(String token) {
            this.token = token;
        }
        public Data getData() {
            return data;
        }
        public void setData(Data data) {
            this.data = data;
        }
        public Notification getNotification() {
            return notification;
        }
        public void setNotification(Notification notification) {
            this.notification = notification;
        }
    }
    
 
    public static class Data {
        String title;
        String content;
        
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
    }
    
    
    public static class Notification {
        String title;
        String body;
        
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
        public String getBody() {
            return body;
        }
        public void setBody(String body) {
            this.body = body;
        }
    }
}
 
cs

 - 푸시 메시지 객체

 

 

Main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
    
    static final String AOS_TOKEN = "...";
    static final String IOS_TOKEN = "...";
    
    
    public static void main(String[] args) {
        String title = "테스트";
        String content = "푸시 발송 테스트입니다!";
        
        Push push = new Push();
        push.send(AOS_TOKEN, title, content);
        push.send(IOS_TOKEN, title, content);
    }
}
 
cs

 

'IT > Ⅲ. 웹' 카테고리의 다른 글

Android, IOS 앱 딥링크 구현  (4) 2025.05.28

Key 발급

Apple Developer Member Center

https://developer.apple.com/account/resources/authkeys/list

 

로그인 - Apple

 

idmsa.apple.com

 

APNs 선택 후 Configure 클릭

 

 

.p8 파일을 다운로드 받는다 (다시 다운받지 못함)

 

 

APN 인증키 업로드

APN 인증 키 업로드 클릭
앞서 다운받은 .p8 파일 업로드, 키 ID 입력

 

App Developer Member Center 에서 Key ID 확인

 

 

GoogleService-Info.plist 파일을 다운받아서 프로젝트에 넣어준다

 



패키지 추가

https://github.com/firebase/firebase-ios-sdk

 

 

Capability 추가

 

 

AppDelegate

@import FirebaseCore;
@import FirebaseMessaging;
#import <UserNotifications/UserNotifications.h>
 
 
@implementation AppDelegate
 
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    [FIRApp configure];
    
    
    // 앱이 포그라운드일때 푸시 알림 수신
    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
    // FCM 토큰 수신콜백
    [FIRMessaging messaging].delegate = self;
    
    // 푸시 알림등록
    UNAuthorizationOptions options = UNAuthorizationOptionAlert|UNAuthorizationOptionSound|UNAuthorizationOptionBadge;
    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if(granted) {
            // Apple 푸시 알림 서비스를 통해 원격 알림을 수신하도록 등록
            dispatch_async(dispatch_get_main_queue(), ^{
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            });
        }
    }];
        
 
    ViewController *main = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"mainVc"];
    self.navigation = [[UINavigationController alloc] initWithRootViewController:main];
    [self.window setRootViewController:self.navigation];
    [self.window makeKeyAndVisible];
    
    return YES;
}
 
 
// APNs 푸시 토큰 받아오기 성공 : 파이어베이스에 등록해야함
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    // APNs 토큰을 Firebase에 등록
    [FIRMessaging messaging].APNSToken = deviceToken;
    
    // 토큰 가져오기
    [[FIRMessaging messaging] tokenWithCompletion:^(NSString * _Nullable token, NSError * _Nullable error) {
        if(error) {
            NSLog(@"FaileToken : %@", error.localizedDescription);
            return;
        }
        NSLog(@"PushToken : %@", token);
    }];
}
 
// FCM 푸시 토큰 받아오기 성공
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
    NSLog(@"FCM Token : %@", fcmToken);
}
 
// FCM 메시지가 notification 일때 - 포그라운드 푸시알림
// 백그라운드일때는 notification 으로 시스템에서 알림 노출
// * fcm은 메시지가 notification, data 2개가 있다
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    NSLog(@"Push Receive Foreground");
    completionHandler(UNNotificationPresentationOptionBanner|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionBadge);
}
 
// FCM 메시지가 data only 일때 (notification 없을때) - 포그라운드 데이터 수신
// content-available:true + Background Modes 일경우 백그라운드에서도 호출되지만 보장안됨
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
 
}
 
// 알림클릭했을때 호출 - data값 가져와서 사용
// ex) 알림클릭해서 특정 페이지로 이동할때
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
    // data 가져오기
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    NSString *title = userInfo[@"title"];
    NSString *content = userInfo[@"content"];
    NSLog(@"Data : %@ , %@", title, content);
}
 
 
@end
 
 
cs

 

 

 

'IT > Ⅰ. IOS' 카테고리의 다른 글

[IOS] TTS 사용  (3) 2025.07.06
[IOS] FCM Crashlytics 로그  (2) 2025.07.06
[IOS] GIF, SVG, APNG 이미지 사용  (0) 2025.05.22
[IOS] 이미지로 프로그레스바 만들기  (0) 2025.05.17
[IOS] PDF 문서 보기 - WKWebView 사용  (0) 2025.05.11

+ Recent posts