# iOS SDK 매뉴얼

{% hint style="info" %}
Xcode 14.1 버전 기반으로 설명하고 있습니다.\
iOS용 핑거푸시 SDK를 다운로드 하신 후 Sample 소스를 참고하시기 바랍니다.
{% endhint %}

## 프로젝트 설정

SDK를 다운로드 받은 후 XCODE에서 프로젝트를 생성합니다.

{% content-ref url="sdk-down" %}
[sdk-down](https://developers.fingerpush.com/app-push/sdk-manual/sdk-down)
{% endcontent-ref %}

1\) 다운 받은 프레임워크(finger.xcframework)를 프로젝트에 추가합니다.

![](https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2Fpnv8qp2nXjQ9qA0qMrFZ%2Fimage1.png?alt=media\&token=cd274724-ae71-43ef-9245-22caabfcb91a)

2\) Xcode에서 TARGETS 선택 후 General 탭에서 'Frameworks, Libraries, and Embedded Content' 항목에 프레임워크(finger.xcframework)가 추가 되었는지 확인합니다. ('Embed\&Sign'로 설정)

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2FcJIy4L4Cvu1SQ0EtPIQW%2Fios_1.png?alt=media&#x26;token=42645c2c-17ce-445b-8c79-1006c6100c16" alt=""><figcaption></figcaption></figure>

## Push Notification의 Entitlements 설정

Target 선택 후 Signing\&Capabilities 탭에서 'Push Notifications'를 추가해주면 자동으로 AppName.entitlements 파일이 생성됩니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2Fcv95ttCqx4IERaU48A7m%2Fios_2.png?alt=media&#x26;token=2d2305d5-1ac6-4c57-be4a-a21d7dad0eff" alt=""><figcaption></figcaption></figure>

## 기기 버전 관리&#x20;

Bundle version(build) 값이 int형이면 따로 AppVersionInt 값을 추가하지 않아도 됩니다.\
int형이 아닌 경우 AppVersionInt 값을 추가하여 설정합니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2FVoGtExhrtg3IqNNZDNAE%2Fios_7.png?alt=media&#x26;token=bd4b247d-5e8a-4676-8bde-040b9b17ba82" alt=""><figcaption></figcaption></figure>

## “ProjectName-Bridging-Header.h” 추가하기&#x20;

1\) Xcode project navigator의 'File>New>File'에서 Header File 선택 후, 'ProjectName-Bridging-Header.h'로 추가합니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2FUGHP0tArP9Il1qjSt4Lx%2Fios_8.png?alt=media&#x26;token=e62ffed5-2d2e-4fa2-a995-5ad021e12449" alt=""><figcaption></figcaption></figure>

2\) build Settings에서 Objective-C Bridging Header에 'ProjectName-Bridging-Header.h'의 경로를 추가합니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2FtmDvHkG4ETPxFO8YH8Qs%2Fios_9.png?alt=media&#x26;token=999994cd-a85d-4534-989c-3c70ff08cc5a" alt=""><figcaption></figcaption></figure>

3\) 'ProjectName-Bridging-Header.h'에 #import \<finger/finger.h>를 추가합니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2FmUxjVBcpmzsDaiw4KOWN%2Fios_10.png?alt=media&#x26;token=c3d83c8c-1047-4c35-b12e-5719470759cc" alt=""><figcaption></figcaption></figure>

## 핑거푸시 연동

1\) 핑거푸시 APP KEY 설정 및 RemoteNotifications 등록

{% hint style="danger" %} <mark style="color:red;">개발용 DeviceToken과 배포용 DeviceToken이 섞이지 않도록 주의해 주십시오.</mark>
{% endhint %}

{% hint style="danger" %} <mark style="color:red;">앱키, 앱시크릿 변경시 기존 설정값들이 적용되지 않을 수 있기 때문에 앱 삭제 후 재설치를 권장드립니다.</mark>
{% endhint %}

{% tabs %}
{% tab title="Swfit" %}

<pre class="language-swift"><code class="lang-swift">/***
AppDelegate에 핑거푸시서버와 연동을 하기 위해서 다음과 같이 설정합니다.
***/

#import UserNotifications

//핑거푸시
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
<strong>        let fingerManager = finger.sharedData()
</strong>
        /*핑거푸시 APP KEY 설정*/   
        #if DEBUG
        //개발용 앱
        fingerManager?.setAppKey("발급받은 앱키")
        fingerManager?.setAppScrete("발급받은 앱시크리트키")
        #else
        // 배포용 앱
        fingerManager?.setAppKey("발급받은 앱키")
        fingerManager?.setAppScrete("발급받은 앱시크리트키")
        #endif
        
        /*RemoteNotifications 등록*/   
        if #available(iOS 10.0, *) {
   
            let center = UNUserNotificationCenter.current()
            center.delegate = self

            center.requestAuthorization(options: [.alert,.badge,.sound], completionHandler: { (granted, error) in
                
                print("granted : \(granted) / error : \(String(describing: error))")
                
                if granted {
                    DispatchQueue.main.async(execute: {
                        application.registerForRemoteNotifications()
                    })
                }
                
            })
    }
    
    ..
    ..
        
}
</code></pre>

{% endtab %}

{% tab title="Objective-C" %}

<pre class="language-objectivec"><code class="lang-objectivec">/***
AppDelegate에 핑거푸시서버와 연동을 하기 위해서 다음과 같이 설정합니다.
***/
 
#import &#x3C;finger/finger.h>
#import &#x3C;UserNotifications/UserNotifications.h>
 
//핑거푸시 
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  {
 
        finger  *_fingerManager = [finger sharedData];   //싱글톤 객체로 사용
        
        /*핑거푸시 APP KEY 설정*/   
<strong>        #ifdef DEBUG
</strong>        //개발용 앱
          [_fingerManager setAppKey:@"발급받은 앱키"];    //App Key
          [_fingerManager setAppScrete:@"발급받은 앱시크리트키"];    //AppScrete
        #else
        //배포용 앱
          [_fingerManager setAppKey:@"발급받은 앱키"];    //App Key
          [_fingerManager setAppScrete:@"발급받은 앱시크리트키"];    //AppScrete
        #endif
        
        /*RemoteNotifications 등록*/
        if (@available(iOS 10.0, *)) {

            UNUserNotificationCenter *userNotificationCenter = [UNUserNotificationCenter currentNotificationCenter];
            userNotificationCenter.delegate = self;

            [userNotificationCenter requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
            
                NSLog(@"granted :%i / error : %@",granted,error);
            
                if (granted) {
                    //허용
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [application registerForRemoteNotifications];
                    });
                }
            
            }];
        
        }
        
        ..
        ..
 
}
</code></pre>

{% endtab %}
{% endtabs %}

2\) 핑거푸시에 기기 등록

{% hint style="danger" %} <mark style="color:red;">DeviceToken은 OS에 의해 변경될 수 있습니다. 따라서, 앱 실행 시마다 호출해야 합니다.</mark>

<mark style="color:red;">핑거푸시 모든 API는 기기 등록 API(register) 성공 후 사용할 수 있습니다.</mark>
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
//기기등록 
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

    //핑거푸시의 모든 api를 사용하기 위해서 기기등록 우선        
    finger.sharedData().registerUser(withBlock: deviceToken, { (posts, error) -> Void in
        if error != nil{
            print("기기 등록 : \(posts)")
        } else {
            //이미등록(504, 201) 무시.
            print("기기 등록 error : \(error)")
        }
    }) 
    
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
//기기등록 
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    
    //핑거푸시의 모든 api를 사용하기 위해서 기기등록 우선
    [[finger sharedData] registerUserWithBlock:deviceToken :^(NSString *posts, NSError *error) {
        if (!error)
        {
            NSLog(@"기기등록  %@", posts);        
        }else{
            //이미등록(504, 201) 무시.
            NSLog(@"기기등록 error %@", error);        
        }
    }];
    
}
```

{% endtab %}
{% endtabs %}

3\) 푸시 메세지 수신 시 메세지 오픈/읽음 처리

{% tabs %}
{% tab title="Swift" %}

<pre class="language-swift"><code class="lang-swift">//메세지 오픈 및 읽음 처리
<strong>func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
</strong>    
    let userInfo = response.notification.request.content.userInfo
    
    //메세지 읽음 처리
    finger.sharedData().requestPushCheck(withBlock: userInfo , { (posts, error) -> Void in
        if error != nil{
            print("check : \(posts)")
        } else {
            print("check error : \(error)")
        }
    })
    
    completionHandler()

}
</code></pre>

{% endtab %}

{% tab title="Objective-C" %}

<pre class="language-objectivec"><code class="lang-objectivec">//메세지 오픈 및 읽음 처리
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {

<strong>    NSDictionary *userInfo = response.notification.request.content.userInfo;
</strong> 
   //메세지 읽음 처리
   [[finger sharedData]  requestPushCheckWithBlock:userInfo :^(NSString *posts, NSError *error) { 
      if (!error) {
          NSLog(@"check : %@", posts);
      }else{
          NSLog(@"check error %@", error);
      }
  )];
  
  completionHandler();
      
}
</code></pre>

{% endtab %}
{% endtabs %}

4\) 푸시 수신 데이터(Payload)

```objectivec
{
   aps = {
      alert = {
            body = "안녕하세요. 핑거푸시입니다";
            title = "메세지 제목입니다.";
         };
      badge = 0; // 뱃지 카운트
      category = fp; // 메세지 카테고리
      "mutable-content" = 1; // notification service extension 사용 여부(이미지와 웹 링크 추가시)
      sound = default; // 사운드
   };
   커스텀 데이터 키1 = 커스텀 데이터 값1;
   커스텀 데이터 키2 = 커스텀 데이터 값2;
   커스텀 데이터 키3 = 커스텀 데이터 값3;
   code = "CD:1;IM:1;WL:1;PT:STOS";
   // ( CD : 커스텀 데이터 여부(0 : 없음, 1 : 있음), IM : 이미지 첨부 여부(0 : 없음, 1 : 있음), WL : 웹 링크 여부(0 : 없음, 1 : 있음), PT : 메세지 타입(DEFT:일반푸시, STOS:Server to Server, LNGT:롱푸시))
   imgUrl = "http://..."; // 이미지 URL
   labelCode = ""; // 라벨 코드
   msgTag = ...; // 메세지 고유 번호
   weblink = "http://www.google.com"; // 웹 링크
}
```

{% hint style="info" %}
푸시 수신 데이터(Payload)에 대한 내용은 아래 링크를 참조 바랍니다[.](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html)
{% endhint %}

{% embed url="<https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html>" %}

## API 연동 결과 코드&#x20;

{% hint style="info" %}
Error.code 로 SDK 내부 오류 또는 서버 오류 여부를 확인할 수 있습니다.

* 900 : SDK 내부 에러 코드
* 901 : 핑거푸시 서버 에러 코드
  {% endhint %}

<table><thead><tr><th width="150">코드</th><th width="300.92802106539887">내용</th><th>비고</th></tr></thead><tbody><tr><td>200</td><td>정상 처리 </td><td></td></tr><tr><td>403</td><td>App_key, secret 오류, 권한 없음</td><td></td></tr><tr><td>404</td><td>조회 대상 없음, 조회 결과 없음</td><td></td></tr><tr><td>500</td><td>처리 중 에러</td><td></td></tr><tr><td>503</td><td>필수 값 없음</td><td></td></tr><tr><td>504</td><td>이미 등록된 토큰</td><td>디바이스 등록에서만 사용</td></tr></tbody></table>

## iOS 10 Rich Notification

{% hint style="info" %}
Xcode 14.1 버전 기반으로 설명하고 있습니다.\
iOS용 핑거푸시 SDK를 다운로드 하신 후 Sample 소스를 참고하시기 바랍니다.
{% endhint %}

### Notification Service Extension 생성

1\) 기존 앱에 새 타겟(Notification Service Extension)을 추가합니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2Fen9wKqZFPwejd6tNtOqI%2Fios_3.png?alt=media&#x26;token=e9655d08-6b16-42f8-8aef-d962e6574284" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2FcMid3g7gCuI38jbl6qPV%2Fios_4.png?alt=media&#x26;token=71ff2588-b540-4e64-90c6-26af44a8af7e" alt=""><figcaption></figcaption></figure>

2\) 새 타겟의 옵션을 각자에 맞게 설정합니다.\
애플 개발자 사이트에서 Notification Service Extension 만의 App ID와 Provisioning Profiles을 생성해줘야 합니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2FTTEH6doT6ZNhHcIlJdf4%2Fios_5.png?alt=media&#x26;token=07367925-fc8e-46e5-b972-ac9c9f3cf7d7" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Embed In Application 설정은 Xcode의 TAGETS/General/Embedded Binaries에서 수정이 가능합니다.
{% endhint %}

3\) 생성된 NotificationService에서 'fingerNotificationService' 클래스를 적용합니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2FJbHsuzBXNj4cq5pQWwRT%2Fios_11.png?alt=media&#x26;token=41a82048-1cee-4aaa-b621-bc92e686a23f" alt=""><figcaption></figcaption></figure>

{% tabs %}
{% tab title="Swift" %}

```swift
/*Rich Notification*/
class NotificationService: fingerNotificationService {
    
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        
        self.disableSyncBadge()
        
        super.didReceive(request, withContentHandler: contentHandler)
        
    }
    
    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        super .serviceExtensionTimeWillExpire()
    }

}
```

{% endtab %}

{% tab title="Objective-C" %}

<pre class="language-objectivec"><code class="lang-objectivec"><strong>//NotificationService.h
</strong><strong>#import &#x3C;UserNotifications/UserNotifications.h>
</strong>#import "fingerNotificationService.h"

@interface NotificationService : fingerNotificationService

@end


//NotificationService.m
@interface NotificationService ()

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    
    [self disableSyncBadge];
    
    [super didReceiveNotificationRequest:request withContentHandler:contentHandler];
    
}

- (void)serviceExtensionTimeWillExpire {
    // Called just before the extension will be terminated by the system.
    // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    [super serviceExtensionTimeWillExpire];
}

@end
</code></pre>

{% endtab %}
{% endtabs %}

###

### Rich Notification 발송

핑거푸시 사용자 콘솔에서 이미지 혹은 웹링크를 넣어 보내면 Rich Notification 형식으로 푸시를 발송합니다.

<figure><img src="https://1606198054-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ff5XCUiUhwc0T57hW21TH%2Fuploads%2Fjon3IIu747t2K4cyfsQU%2F%EA%B7%B8%EB%A6%BC57.png?alt=media&#x26;token=ff14d04a-3f9c-4d50-aa2a-9f4c40584052" alt=""><figcaption></figcaption></figure>

### 참조 링크

* 핑거푸시 샘플 다운로드

{% content-ref url="sdk-down" %}
[sdk-down](https://developers.fingerpush.com/app-push/sdk-manual/sdk-down)
{% endcontent-ref %}

* 애플 개발자 사이트 UNNotificationServiceExtension

{% embed url="<https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension?preferredLanguage=occ>" %}
