iOS SDK
    • PDF

    iOS SDK

    • PDF

    Article Summary

    Classic/VPC 환경에서 이용 가능합니다.

    iOS 앱의 보안을 위한 App Safer iOS SDK 사용 방법에 대해 설명합니다. SDK를 설치하고 환경을 구성함으로써 App Safer를 연동할 수 있습니다.

    참고

    App Safer를 적용하는 전반적인 샘플 코드는 샘플 코드에서 확인해 주십시오.

    SDK 설치 및 환경 구성

    App Safer에서 제공하는 기능을 이용하려면 먼저 iOS SDK를 설치한 후 환경을 구성해 주십시오. iOS 앱용 App Safer의 라이브러리는 하나의 프레임워크로 구성되어 있으며, Bitcode Enable/Disable 환경을 모두 지원합니다. 구성하는 방법은 다음과 같습니다.

    참고

    Xcode 8.0 이상의 환경에서 빌드하는 것을 권장합니다.

    1. 다운로드한 SDK를 임의의 디렉터리에서 압축 해제해 주십시오.
    2. 프로젝트의 Bitcode 설정을 확인해 주십시오.
      • 경로: Build Settings > Build Options > Enable Bitcode
    3. App Safer 프레임워크를 프로젝트에 추가해 주십시오.
      • 경로: File > Add Files to "Your Project"... > Options > Copy items if needed 선택 > AppSaferFramework.framework 선택 > Add 클릭
    4. Swift를 사용하는 경우 Objective-C와의 호환을 위해 Bridging Header를 생성해 주십시오.
      • 헤더 파일 생성: File > New File... > Header File 선택 > 프로젝트 루트 위치에 파일명 'AppSaferFramework-Bridging-Header.h'으로 설정
      • 헤더 파일을 빌드 설정에 추가: Build Settings > Swift Compiler - General > Objective-C Bridging Header > AppSaferFramework-Bridging-Header.h에서 다음 코드 입력
        #ifndef AppSaferFramework_Bridging_Header_h
        #define AppSaferFramework_Bridging_Header_h
        
        #import <AppSaferFramework/AppSaferFramework.h>
        
        #endif /* AppSaferFramework_Bridging_Header_h */
        

    디버깅 방지 기능 적용

    디버깅 방지 기능은 SDK를 설치하면 자동으로 적용됩니다. 만약 디버깅이 필요한 경우 App Safer SDK를 일시적으로 적용 해제한 상태에서 사용해 주십시오.

    캡처 차단 및 탐지 기능 적용

    App Safer SDK에서 제공하는 앱 미리 보기 화면 보호, 스크린샷 탐지, 녹화 및 미러링 시 화면 보호 기능을 적용하려면 API를 호출해야 합니다.

    • iOS 13.0 미만: AppDelegate에서 앱 생명 주기에 맞춰 App Safer API 호출
    • iOS 13.0 이상: SceneDelegate에서 앱 생명 주기에 맞춰 App Safer API 호출

    API를 호출하는 예제는 다음과 같습니다.
    selector를 등록하면 캡처 이벤트 탐지 시 callback을 받고 원하는 동작을 수행할 수 있습니다.

    AppDelegate (Swift)
    import UIKit
    
    @main
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
        @objc func didDetectCapture() -> Void  {
            print("[DETECT] Detected Screenshot in AppDelegate");
        }
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            AppSafer.registerScreenProtectionObserver(window, observer: self, selector: #selector(didDetectCapture))
            return true
        }
    
        func applicationWillResignActive(_ application: UIApplication) {
            AppSafer.preventScreenshot(window, isInvisible: 0)
        }
    
        func applicationDidEnterBackground(_ application: UIApplication) {
            AppSafer.preventScreenshot(window, isInvisible: 1)
        }
    
        func applicationWillEnterForeground(_ application: UIApplication) {
            AppSafer.preventScreenshot(window, isInvisible: 0)
        }
    
        func applicationDidBecomeActive(_ application: UIApplication) {
            AppSafer.preventScreenshot(window, isInvisible: 1)
        }
    }
    
    AppDelegate (Objective-C)
    #import "AppDelegate.h"
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @interface AppDelegate ()
    @end
    
    @implementation AppDelegate
    
    - (void)didDetectCapture {
        NSLog(@"[DETECT] Detected Screenshot in AppDelegate");
    }
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey,id> *)launchOptions {
        [AppSafer registerScreenProtectionObserver:_window observer:self selector:@selector(didDetectCapture)];
        
        return YES;
    }
    
    - (void)applicationWillEnterForeground:(UIApplication *)application {
        [AppSafer preventScreenshot:_window isInvisible:false];
    }
    
    - (void)applicationDidBecomeActive:(UIApplication *)application {
        [AppSafer preventScreenshot:_window isInvisible:false];
    }
    
    - (void)applicationWillResignActive:(UIApplication *)application {
        [AppSafer preventScreenshot:_window isInvisible:true];
    }
    
    - (void)applicationDidEnterBackground:(UIApplication *)application {
        [AppSafer preventScreenshot:_window isInvisible:true];
    }
    @end
    
    SceneDelegate (Swift)
    import UIKit
    import SwiftUI
    
    class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
        var window: UIWindow?
    
        @objc func didDetectCapture() -> Void  {
            print("[DETECT] Detected Screenshot in AppDelegate");
        }
        
        func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
            let contentView = ContentView()
    
            if let windowScene = scene as? UIWindowScene {
                let window = UIWindow(windowScene: windowScene)
                window.rootViewController = UIHostingController(rootView: contentView)
                self.window = window
                window.makeKeyAndVisible()
                
                AppSafer.registerScreenProtectionObserver(window, observer: self, selector: #selector(didDetectCapture))
            }
        }
    
        func sceneDidBecomeActive(_ scene: UIScene) {
            AppSafer.preventScreenshot(window, isInvisible: 0)
        }
    
        func sceneWillResignActive(_ scene: UIScene) {
            AppSafer.preventScreenshot(window, isInvisible: 1)
        }
    
        func sceneWillEnterForeground(_ scene: UIScene) {
            AppSafer.preventScreenshot(window, isInvisible: 0)
        }
    
        func sceneDidEnterBackground(_ scene: UIScene) {
            AppSafer.preventScreenshot(window, isInvisible: 1)
        }
    }
    
    
    SceneDelegate (Objective-C)
    #import "SceneDelegate.h"
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @interface SceneDelegate ()
    @end
    
    @implementation SceneDelegate
    
    - (void)didDetectCapture {
        NSLog(@"[DETECT] Detected Screenshot in SceneDelegate");
    }
    
    - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)) {
        [AppSafer registerScreenProtectionObserver:_window observer:self selector:@selector(didDetectCapture)];
    }
    
    - (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
        [AppSafer preventScreenshot:_window isInvisible:false];
    }
    
    - (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
        [AppSafer preventScreenshot:_window isInvisible:false];
    }
    
    - (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
        [AppSafer preventScreenshot:_window isInvisible:true];
    }
    
    - (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0))  {
        [AppSafer preventScreenshot:_window isInvisible:true];
    }
    
    @end
    

    제공 API

    App Safer API는 2개의 패키지를 통해 제공되며, 각 패키지에서 호출 가능한 API는 다음과 같습니다.

    • AppSafer
    이름설명
    initAppSaferAppSafer을 사용하기 위해 초기화
    checkTampering실시간 보안 탐지
    • Jailbreak 탐지
    • Simulator 탐지
    • Debugging 탐지
    • Memory Tampered 탐지
    • Unauthorized Signature 탐지
    setUserId사용자 식별자 설정
    • AppSaferDelegate
      • 비동기로 동작하는 Callback 함수입니다.
      • 결과 처리는 AppSaferDelegate를 통해 위임됩니다.
      • 검사 결과를 받으려면 AppSaferDelegate를 구현한 후 initAppSafer 함수를 이용해 등록해야 합니다.
      • Swift를 사용할 경우 struct가 아닌 class에 구현해야 하며 AppSaferDelegate와 NSObject를 모두 추가해야 합니다.
    이름필수 여부설명
    appSaferDidInitFinish필수App Safer의 초기화 결과 확인
    appSaferDidCheckTamperingFinish필수checkTampering 함수 수행 결과 확인
    appSaferDetectedJailbreak선택기기의 탈옥 행위 탐지 시 호출
    appSaferDetectedSimulator선택기기가 가상 머신에서 실행 중임을 탐지 시 호출
    appSaferDetectedDebugging선택디버깅 행위 탐지 시 호출
    appSaferDetectedMemoryTampered선택앱의 메모리 변조 탐지 시 호출

    initAppSafer

    App Safer는 초기화를 성공해야만 사용할 수 있습니다. App Safer를 초기화하려면 아래 코드를 사용해 주십시오.
    로그를 전송하는 데 필요한 정보 및 전역으로 사용되는 변수가 초기화됩니다.

    • 초기화 성공 여부를 전달받으려면 AppSaferDelegate를 구현해야 합니다.
    func initAppSafer(_ delegate: AppSaferDelegate!, serviceCode: String!, key appsaferKey: String!) -> Int32
    
    - (int) initAppSafer:(id<AppSaferDelegate>)delegate serviceCode:(NSString *)serviceCode key:(NSString *)appsaferKey
    
    • 매개변수

      매개변수설명
      delegateAppSaferDelegate가 구현된 인스턴스
      serviceCodeApp Safer를 이용하기 위한 코드
      네이버 클라우드 플랫폼 사용자는 반드시 'ncloud'를 전달
      appsaferKey콘솔에서 앱 등록 시 생성된 App Safer Key 값
    • 반환 값

      반환 값설명
      SUCCESS(0)성공
      FAIL(-1)실패
    • 예제

      struct ContentView: View {
         func initAppSaferExample() {
            // APP_SAFER_KEY generated when registering an app to the Console
            let result = AppSafer().initAppSafer(AppSaferDelegator.delegator, serviceCode: "ncloud", key: "<APP_SAFER_KEY>")
      
            NSLog("initAppSafer() result: %d", result);
      
            if(result == SUCCESS) {
                  // init success
            } else if(result == FAIL) {
                  // init fail
            }
         }
         
         var body: some View {
            Button("initAppSafer") {
                  initAppSaferExample()
            }
         }
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (IBAction)initAppSaferExample:(id)sender {
         AppSafer *appSafer = [[AppSafer alloc] init];
      
         int res = FAIL;
         if(appSafer != nil) {
            // APP_SAFER_KEY generated when registering an app to the Console
            res = [appSafer initAppSafer:self serviceCode:@"ncloud" key:@"<APP_SAFER_KEY>"];
            
            NSLog(@"initAppSafer() result: %d", res);
      
            if(res == SUCCESS) {
                  // init success
            }
         }
      }
      

    checkTampering

    실시간 보안 탐지 기능을 실행하려면 아래 코드를 사용해 주십시오.

    func checkTampering()
    
    - (int)checkTampering
    
    • 반환 값

      반환 값설명
      SUCCESS(0)검사 시작 성공
      FAIL(-1)검사 시작 실패
      BLOCK(2)보안 정책을 위반하여 차단
      BEFOREINIT(3)App Safer가 초기화되지 않음
    • 예제

      struct ContentView: View {
          func checkTamperingExample() {
              let result = AppSafer().checkTampering()
              
              switch(result) {
              case FAIL:
                  print("Failed to check tampering")
                  break
              case SUCCESS:
                  print("Check Tampering Success")
                  break
              case BLOCK:
                  print("Device is blocked")
                  break
              case BEFOREINIT:
                  print("AppSafer is not initialized")
                  break
              default:
                  break
              }
          }
          
          var body: some View {
              Button("checkTampering") {
                  checkTamperingExample()
              }
          }
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (IBAction)checkAppSafer:(id)sender {
          AppSafer *appSafer = [[AppSafer alloc] init];
          
          if(appSafer != nil) {
              int res = [appSafer checkTampering];
              
              switch(res) {
                  case FAIL:
                      NSLog(@"Failed to check tampering");
                      break;
                  case SUCCESS:
                      NSLog(@"Check Tampering Success");
                      break;
                  case BLOCK:
                      NSLog(@"Device is blocked");
                      break;
                  case BEFOREINIT:
                      NSLog(@"AppSafer is not initialized");
                      break;
              }
          } else {
              NSLog(@"AppSafer is nil");
          }
      }
      
      @end
      

    setUserId

    초기화 및 탐지 이벤트 발생 시 App Safer 서버로 전송되는 로그에 사용자 식별자를 포함하려면 아래 코드를 사용해 주십시오.

    func setUserId(_ userId: String!) -> Int32
    
    - (int)setUserId:(NSString *)userId
    
    • 매개변수

      매개변수설명
      userId사용자 식별자
    • 반환 값

      반환 값설명
      SUCCESS(0)설정 성공
      FAIL(-1)설정 실패
    • 예제

      struct ContentView: View {
         func setUserIdExample(_ userId: String) {
            print("setUserId(\(userId))")
            
            let result = AppSafer().setUserId(userId)
            
            switch(result) {
            case FAIL:
                  print("Failed to set userId: \(userId)")
                  break
            case SUCCESS:
                  print("setUserId() Success: \(userId)")
                  break
            default:
                  break
            }
         }
         
         var body: some View {
            Button("setUserId") {
                  setUserIdExample("ExampleUserId")
            }
         }
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (IBAction)setUserId:(id)sender {
         AppSafer *appSafer = [[AppSafer alloc] init];
         
         if(appSafer != nil) {
            NSLog(@"setUserId(%@)", [self.useridText text]);
            
            int res = [appSafer setUserId:[self.useridText text]];
      
            switch(res) {
                  case FAIL:
                     NSLog(@"Failed to set userId");
                     break;
                  case SUCCESS:
                     NSLog(@"setUserId Success");
                     break;
            }
         } else {
            NSLog(@"AppSafer is nil");
         }
      }
      

    appSaferDidInitFinish

    initAppSafer 함수 호출 후 초기화 결과를 전달하기 위해 아래 함수가 호출됩니다.

    func appSaferDidInitFinish(_ result: Int32)
    
    - (void)appSaferDidInitFinish:(int)result
    
    • 매개변수

      매개변수설명
      SUCCESS(0)초기화 성공
      FAIL(-1)초기화 실패
      BLOCK(2)보안 정책 위반으로 차단됨
    • 예제

      func appSaferDidInitFinish(_ result: Int32) {
         print("appSaferDidInitFinish result: \(result)");
         if(result == BLOCK) {
            print("Device is blocked!");
            // add to exit application logic
         }
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (void)appSaferDidInitFinish:(NSUInteger)result msg:(NSString *)message {
         NSLog(@"appSaferDidInitFinish result: %d", result);
         if(result == BLOCK) {
            NSLog(@"Device is blocked!");
            // add to exit application logic
         }
      }
      

    appSaferDidCheckTamperingFinish

    checkTampering 함수의 수행 결과를 전달하기 위해 아래 함수가 호출됩니다.

    func appSaferDidCheckTamperingFinish(_ result: Int32)
    
    - (void)appSaferDidCheckTamperingFinish:(int)result
    
    • 매개변수

      매개변수설명
      FAIL(-1)검사 실패
      SAFE(0)이벤트가 탐지되지 않음
      DETECT(1)이벤트 탐지
      BLOCK(2)차단됨
    • 예제

      func appSaferDidCheckTamperingFinish(_ result: Int32) {
         print("appSaferDidCheckTamperingFinish result: " + (
                  result == FAIL   ? "FAIL" :
                  result == SAFE   ? "SAFE" :
                  result == DETECT ? "DETECT" :
                  result == BLOCK  ? "BLOCK": "UNKNOWN"))
      
         if(result == BLOCK) {
            print("Device is blocked!")
            // add to exit application logic
         }
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (void)appSaferDidCheckTamperingFinish:(int)result {
         NSLog(@"appSaferDidCheckTamperingFinish result: %@",
               result == FAIL   ? @"FAIL" :
               result == SAFE   ? @"SAFE" :
               result == DETECT ? @"DETECT" :
               result == BLOCK  ? @"BLOCK": @"UNKNOWN");
      
         if(result == BLOCK) {
            NSLog(@"Device is blocked!");
            // add to exit application logic
         }
      }
      

    appSaferDetectedJailbreak

    기기의 탈옥이 탐지될 때 아래 함수가 호출됩니다. checkTampering 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용할 수 있습니다.

    func appSaferDetectedJailbreak()
    
    - (void)appSaferDetectedJailbreak
    
    • 예제

      func appSaferDetectedJailbreak() {
         print("[DETECT] appSaferDetectedJailbreak");
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (void)appSaferDetectedJailbreak {
         NSLog(@"[DETECT] appSaferDetectedJailbreak");
      }
      

    appSaferDetectedSimulator

    앱이 가상 머신에서 실행 중임이 탐지될 때 아래 함수가 호출됩니다. checkTampering 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용할 수 있습니다.

    func appSaferDetectedSimulator()
    
    - (void)appSaferDetectedSimulator
    
    • 예제

      func appSaferDetectedSimulator() {
         print("[DETECT] appSaferDetectedSimulator");
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (void)appSaferDetectedSimulator {
         NSLog(@"[DETECT] appSaferDetectedSimulator");
      }
      

    appSaferDetectedDebugging

    기기에서 디버깅이 탐지될 때 아래 함수가 호출됩니다. checkTampering 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용할 수 있습니다.

    func appSaferDetectedDebugging()
    
    - (void)appSaferDetectedDebugging
    
    • 예제

      func appSaferDetectedDebugging() {
         print("[DETECT] appSaferDetectedDebugging");
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (void)appSaferDetectedDebugging {
         NSLog(@"[DETECT] appSaferDetectedDebugging");
      }
      

    appSaferDetectedMemoryTampered

    메모리 변조가 탐지될 때 아래 함수가 호출됩니다. checkTampering 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용할 수 있습니다.

    func appSaferDetectedMemoryTampered()
    
    - (void)appSaferDetectedMemoryTampered
    
    • 예제

      func appSaferDetectedMemoryTampered() {
         print("[DETECT] appSaferDetectedMemoryTampered");
      }
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      @implementation ViewController
      
      - (void)appSaferDetectedMemoryTampered {
         NSLog(@"[DETECT] appSaferDetectedMemoryTampered");
      }
      

    이 문서가 도움이 되었습니까?

    What's Next
    Changing your password will log you out immediately. Use the new password to log back in.
    First name must have atleast 2 characters. Numbers and special characters are not allowed.
    Last name must have atleast 1 characters. Numbers and special characters are not allowed.
    Enter a valid email
    Enter a valid password
    Your profile has been successfully updated.