IT_Programming/Objective-C · Swift · iOS

[펌] 아이폰 6, 6+, iOS 8으로의 포팅: 10가지 팁

JJun ™ 2015. 9. 23. 11:42



 출처: http://khanrc.tistory.com/entry/%EC%95%84%EC%9D%B4%ED%8F%B0-6-6-iOS-8%EC%9C%BC%EB%A1%9C%EC%9D%98-%ED%8F%AC%ED%8C%85-10%EA%B0%80%EC%A7%80-%ED%8C%81



Porting Your App to the iPhone 6, iPhone 6 Plus and iOS 8: Top 10 Tips

레이웬더리치 블로그는 iOS 개발하면서 많은 도움을 얻었던 곳이다. 다국어 서비스를 지원해서 한국어로 된 포스트들도 있다.
물론, 여느 자료들이 다 그렇듯이, 최신 포스트는 영어다 :(

1년여 간 쉬었던 iOS 개발을 다시 시작하면서, 그동안 많은 것들이 바뀌었다. iOS 8과 아이폰 6, 6+ 가 대표적이다.
이를 공부하기 위해 이 글을 번역한다.

레이웬더리치 블로그는 사용자가 직접 번역자가 되어 글을 번역 해 올릴 수 있고, 등록하고 메일을 보내 권한을 얻을 수 있다.
나는 예전에도 푸쉬알림에 대한 포스트를 번역했었고 이 블로그에 등록하려고 권한까지 얻었지만 결국 등록하진 않았다.
혼자 번역해서 내 블로그에 올리는 것과 이 블로그에 올리는 것은 많은 차이가 있어서, 한번 다듬어서 올려야겠다고 생각했는데
끝까지 하지 못했다 -_-;;

이 글도 전문을 번역하기보다는 요약 번역을 하려고 생각하고 있어서 가볍게 내 블로그에 정리하기로 한다.


iOS 8 에서 universal storyboards가 등장했다.
이걸 반기든 그렇지 않든, 암튼 이를 지원해야 하고 결국 기존 앱들은 포팅이 필요하다.
자, 그럼 이에 관한 10가지 팁을 소개한다.


Getting Started

기존의 앱이 아이폰 6+에서 잘 돌아가겠지만 그게 우리가 할 일이 없다는 걸 의미하는 건 아니다.
기존의 앱들은 애플이 지원하는Scale Mode에서 작동하는데, 처음엔 잘 돌아가는거 같아 보이겠지만
자세히 보면 스테이터스 바도 커져 있는 것을 확인할 수 있다.



왼쪽이 scaled mode, 오른쪽이 fullscreen mode다. 풀스크린 모드는 좀 더 많은 정보를 보여주고,
스테이터스 바의 크기도 적당한 것을 볼 수 있다. 글씨 크기가 좀 작아 보일 수 있지만 레티나 디스플레이에서 충분하다.

자, 그럼 풀스크린 모드를 지원하기로 했다면, 한가지 의문이 생긴다
iOS 7은 버려도 되나?

결정하기 전에 아래 사항들을 고려하자:

  • 만약 우리가 iOS 7을 버려도, iOS 7 유저들은 현재 버전을 계속 앱스토어에서 만나볼 수 있다
  • large screen device, 즉 아이폰 6, 6+ 는 모두 iOS 8 이상이다
  • iOS 8 의 점유율이 비록 조금 느리긴 하지만 벌써 60%를 넘었다 (2014/12/23 에 작성됨)
  • 새로운 API들은 iOS 7 에선 사용이 불가능하다



마음을 정했다면, 이제 3가지 섹션으로 구성된 10개의 팁이 여기에 있다!

Note: iOS 7 을 지원하기로 결정했더라도 새 API들을 사용할 수 있다. 
Supporting Multiple iOS Versions and Devices를 참고하자.



Section 1 - 새 스크린 사이즈 지원하기

Tip 1: Adaptive Layout과 Universal Storyboard를 적용해라

만약 이미 스토리보드와 오토레이아웃을 사용하고 있다면, 간단하다. 그렇지 않다면, 지금이 바로 사용할 타이밍이다.
Size 클래스는 오토레이아웃을 필요로 한다
1. 또한 유니버셜 스토리보드에서 보이듯, 애플이 스토리보드를 밀고 있다.
즉, 스토리보드는 갈수록 점점 더 필수가 되어갈 것이다.

심지어, 최신의 WatchKit SDK는 스토리보드 없이는 작동하지 않는다.

만약 스토리보드와 오토레이아웃에 대해 잘 모른다면, 아래의 튜토리얼을 추천한다:

Adaptive layout을 적용하는 첫번째 스텝은 기존의 스토리보드를 universal storyboard으로 전환하는 것이다
— 이는 스토리보드가 다양한 스크린 사이즈에 대응할 수 있게 해준다.

이제 스토리보드를 열고, info 패널로 가서(cmd + alt + 1), Use Size Classes 박스에 체크하자.



이러면 모든 뷰가 정사각형이 되는데, 어떤 스크린 사이즈에도 대응하기 위한 방법이다.
이제 
Assistant Editor의 Preview 모드에서 뷰들을 확인할 수 있다:



이제 각 사이즈 클래스마다 제약(수치)을 조절할 수 있다.
어댑티브 레이아웃, 사이즈 클래스, 유니버셜 스토리보드에 대해 상세한 튜토리얼인 Beginning Adaptive Layout을 참고하자.

Note: 만약 앱이 유니버셜이라서 아이폰용과 아이패드용 각각의 스토리보드를 사용하고 있었다면, 두가지 옵션이 있다
: 하나로 합치든지, 두개로 분리된 걸 유지하든지. 어떻든, 최소 하나는 유니버셜 스토리보드를 만들어야 한다.


Tip 2: Fullscreen Mode와 Launch Screen File을 enable 해라

위에서 봤듯이 풀스크린 모드가 스케일 모드보다 좋다. 또한 adaptive layout은 풀스크린 모드가 아니면 아무 의미가 없다.
다행히도, 풀스크린 모드를 enable하는 것은 굉장히 쉽고 +@의 보너스까지 있다!

애플에 따르면:

런타임에 시스템은 스토리보드 런치 스크린 파일을 찾는다. 따라서 우리의 앱이 아이폰 6의 스크린 사이즈를 지원한다는 것을
시스템에게 알리기 위해 앱의 번들에 스토리보드 런치 스크린 파일을 포함시켜야 한다.

만약 파일이 존재한다면, 시스템은 우리 앱이 아이폰 6, 6+를 지원한다고 생각하고 풀스크린 모드로 실행된다.

잠깐, launch screen storyboard? 아마 이런 질문을 할 것이다: “그럼 더이상 20개의 런치 스크린 이미지들2이 필요 없는거야?”

바로 그거다!

New File > iOS > User Interface에서 Launch Screen 이라는 새로운 파일 타입이 있는데 이를 통해 런치 스크린을 만들 수 있다.


꽤 웃기게도 지금까지 계속 스토리보드에 대해 이야기했는데 런치 스크린은 xib다.
안의 내용물을 지우고 원하는 대로 채워 넣자.

이전과 같이 하고 싶다면 UIImageView를 넣으면 된다.

마지막으로 프로젝트의 제너럴 셋팅에 가서 Launch Screen File탭에 방금 만든 xib파일을 선택해주자:


아이폰 6+ 시뮬레이터로 앱을 돌려보아라.
새로운 런치스크린과 경이로운 풀스크린 모드를 감상할 수 있을 것이다!

만약 iOS 7 이하를 지원한다면: 여전히 4인치 런치 이미지도 필요하다. 만약 하지 않으면 네 앱이 3.5인치 모드에서 작동할 것이다.


Tip 3: Better-Than Retina Displays and @3x Images

아이폰 6+ 는 새로운 Retina HD display와 401 PPI를 지원한다. 이를 위해 @2x처럼 @3x이미지들이 필요하다.

아이폰 6 또한 Retina HD display지만 기존의 레티나와 동일한 pixel density를 갖고 있어서 여전히 @2x 파일을 사용한다.



Section 2 - 유저 퍼미션 변경

iOS 8에서 유저가 좋아할 만한 프라이버시 취급 정책 변화가 있었다. 이에 대한 처리를 제대로 하지 않으면 앱이 뻗을 수 있다.
이 섹션에서는 이에 대한 세가지 팁을 제공한다.


Tip 4: 위치정보 권한 요청 변경

iOS 8 은 유저의 위치에 대한 새로운 두가지 퍼미션을 요청한다: 각각 앱이 작동할 때와 앱이 작동하지 않을 때
위치정보를 업데이트 하는 퍼미션이다.

이전에는 앱이 위치정보를 얻어오려고 하면 자동으로 유저에게 퍼미션을 요청했다.
iOS 8부터는 위치정보를 가져오기 전에 명시적으로 퍼미션을 요청해야 한다.

이를 위해, CLLocationManager에서 requestWhenInUseAuthorization이나 requestAlwaysAuthorization를 명시적으로 불러줘야 한다.
startUpdatingLocation을 부르기 전에 간단하게 추가해주자.
간단한 예시를 소개한다:

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];


마지막으로: 
info.plist에 NSLocationWhenInUseUsageDescription나 NSLocationAlwaysUsageDescription를 새로운 키로 추가해줘야 한다.
Value에는 유저에게 퍼미션을 요청할 코멘트를 넣어주자. 예를 들어, “Location is required to show you nearby items.”






Tip 5: 푸쉬알림 등록 변경

유저 notification 퍼미션도 주로 actionable notifications를 지원하는 방향으로 변경되었다.
모든 기존의 API들은 deprecated 되어 iOS 8에선 작동하지 않는다.

이제 노티피케이션 퍼미션에는 두 layer가 존재한다. 우리의 앱은 먼저 특정 타입의 노티피케이션을 display하기 위한 퍼미션을 요청한다.
유저가 이를 승인하고 나면, 이러한 노티피케이션을 받기 위한 퍼미션을 따로 요청한다.

예전에는 -application:didFinishLaunchingWithOptions:에서 -registerForRemoteNotificationTypes:를 호출하고
스테이터스를 체크하는
델리게이트 콜백을 받았다.
만약 iOS 8에서 동일하게 했다면 델리게이트 메소드가 전혀 호출되지 않을 것이다.

이는 먼저 first layer 의 퍼미션을 요청해야 하기 때문이다. 간단한 예시를 참고하자:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // 1
  UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
  // 2
  [application registerUserNotificationSettings:settings];
  return YES
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
  // 3
  if (notificationSettings.types != UIUserNotificationTypeNone) {
    // 4
    [application registerForRemoteNotifications];
  }
}
// 5
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  // ... (no changes needed)
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
// ... (no changes needed)
}

예전에 못보던 콜백 펑션 하나가 새로 생겼다. 이 과정에 대한 간단한 설명이다:

  1. 일단 UIUserNotificationSettings를 만들어야 한다.
    이 셋팅 오브젝트는 우리의 앱에 필요한 노티피케이션들의 타입을 정의하고, 어떤 액션 카테고리인지도 결정한다.

  2. 이제 -registerUserNotificationSettings:를 호출하고 셋팅 오브젝트를 파라메터로 넘겨주자. 이녀석이 유저에게 퍼미션을 요청한다.

  3. 유저가 응답하면, 새로운 델리게이트 메소드인 -application:didRegisterUserNotificationSettings:가 불린다.
    notificationSettings은 유저가 승인한 퍼미션들을 담고 있기 때문에 스텝 2에서 우리가 보낸 셋팅 오브젝트와는 다를 수 있다.
    여기서 어떤 퍼미션들이 승인되었는지 ‘types’를 체크해주자.

  4. 만약 유저가 우리의 요청을 승인했다면 이제 -registerForRemoteNotifications를 부를 수 있다.
    예전과는 달리 파라메터가 필요하지 않다는 걸 체크하자. 그 파라메터들은 이미 셋팅 오브젝트에 담겨 넘어갔고,
    여기서는 노티피케이션을 받기 위한 요청만 하면 된다.

  5. 이제 디바이스토큰이 넘어오고 이전과 동일한 과정을 진행한다.

Tip 4와는 달리 단지 코드레벨의 변화인 것으로 보인다. 왜 이렇게 변경된지는 모르겠지만…


Tip 6: 친절한 퍼미션 요청

퍼미션 요청 프롬프트가 처음 떴을 때 거절해버리면, 다시는 그 창이 뜨지 않는다.
만약 유저가 필수적인 퍼미션 요청을 거절했을 경우, 에러를 띄우고 Settings\Privacy로 보내 필요한 퍼미션을 enable하도록 하는 것이
일반적이다. 글만 봐도 느껴지지만 이는 썩 별로인 방식이고 많은 앱들이 이러한 방식 때문에 낮은 평점을 받곤 한다.

iOS 8은 이러한 작업들을 UIApplicationOpenSettingsURLString을 통해 단순화했다.
이것은 그냥 constant string으로, 아래와 같이 -openURL:을 통해 셋팅 페이지로 이동한다.
이는 퍼미션 요청을 매우 심플하게 만들어준다.

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];



Section 3 - 포팅을 넘어서

이제 우리의 앱은 iOS 8에서 잘 작동한다! 그러나 아직 iOS 8의 새로운 API들이 남아있다.

Tip 7: 스위프트

스위프트는 다양한 장점을 가지고 있다. 대표적으로 파일의 수와 코드 라인의 수를 줄여준다.
어떤 존재하는 코드던 다시 작성할 필요가 없다. 스위프트는 기존의 프로젝트에도 문제없이 적용할 수 있다.

스위프트와 Obj-C가 우리의 프로젝트에서 잘 동작하도록 하기 위한 팁들이다:

  1. 우리의 프로젝트에 첫 스위프트 파일을 추가할 때 Xcode가 brdging header를 만들어줄 것이다. 이것을 allow하도록 하자.

  2. 스위프트 파일에서 Obj-C 클래스를 사용하고 싶다면, #import를 사용해서 bridging header로 Obj-C 헤더 파일을 임포트하면 된다.

  3. Obj-C 에서 스위프트 클래스를 사용하고 싶다면, 상위 헤더파일인 ProductModuleName-Swift.h를 .m파일에 임포트해라 -ProductModuleName이 우리 모듈의 이름인 경우. 대부분 이것은 프로젝트명이지만,
      프로젝트 셋팅의 
    Product Module Name에서 더블클릭하여 변경할 수 있다.

  4. 스위프트 클래스는 반드시 Obj-C클래스를 상속받거나 @objc라고 마킹해야 한다.


스위프트에 대해 더 공부하고 싶으면 
Swift tutorialsiOS tutorial books 를 참고하란다.
그보다, 애플 공식 책(한국 번역도 있다) 을 먼저 공부하는 게 좋지 않을까 싶다.
내가 스위프트를 잘 몰라서, 위 내용이 이해가 잘 안가므로 원문을 참고하자.



Tip 8: 주요 API 변경사항

iOS 8 은 코코아 터치의 핵심적인 부분에서 변경이 있었다. 
UIAlertViewUIActionSheetUISearchDisplayController 를 대체하는 새로운 클래스들이 등장했고,
뷰 컨트롤러 프레젠테이션 프로세스에서 UIPresentationController 가 더욱 중요해졌다.

UIAlertController는 UIAlertView와 UIActionSheet 둘 다를 대체한다. 깔끔한 블럭 기반의 인터페이스를 지원한다:

UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Are you sure?" message:@once deleted this item cannot be recovered." preferredStyle:UIAlertControllerStyleAlert];
[alert addAction: [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [self deleteItem ]}];
[alert addAction: [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:{}];
[self presentViewController:alert animated:YES completion:nil];

직관적이고 편리하게 변했다. 더 이상 델리게이트가 필요 없고, -presentViewController:로 화면에 띄운다. 
UIAlertController는 버튼이나 텍스트필드 추가 등의 새로운 기능을 지원한다.

NSHipster의 UIAlertController를 참고하자.

UIPresentationController는 뷰 컨트롤러를 presenting 할 때의 모든 컨트롤을 제공한다.
프레젠테이션에서 크롬, 포지션, 애니메이션 등을 모두 깔끔하고 재사용 가능한 방법으로 조정가능하다.

프레젠테이션 컨트롤러에 대해서는 공식 문서를 참조하거나, iOS 8 by Tutorials에서 챕터 6을 참조하자.



Tip 9: Cool New Visual Effects

iOS 7에서 블러효과는 인기 많은 이펙트 중 하나였다.
이에 애플은 iOS 8에서 UIVisualEffectView와 UIVibrancyEffectView라는 클래스를 제공한다!


UIVisualEffectView(좌)는 배경이 조금 무시되는 효과가 있다.
반면 UIVibrancyEffectView(우)는 전경이 한 눈에 확 들어오도록 만들어준다.
이미지 프로세싱인 만큼, 물론 최적화되었지만, 너무 많이 사용할 경우 앱이 느려질 수 있으니 조심하자.

비주얼 이펙트에 대해 더 공부하고 싶으면 iOS 8 Visual Effects Tutorial를 참고하자.



Tip 10: A New World of Options

지금까지 잘 따라왔다면, 이제 우리의 앱은 iOS 8에서 잘 작동할 것이다.
그러나, iOS 8에는 여전히 수많은 것들이 남아 있다!

iOS 8의 몇가지 새로운 기능들을 소개한다:

  • WatchKit3을 사용해서 앱에 와치 익스텐션을 추가해라.
  • 유저가 알림센터에서 정보를 볼 수 있도록 Today Extension을 추가해라.
  • 유저가 앱간 파일공유를 할 수 있도록 Document Providers를 사용해라.
  • 알림에 Actions를 추가해라.
  • 유저가 편하게 인증할 수 있도록 Touch ID를 통합해라.

이 뿐만 아니라 수많은 것들이 더 있다.
더 공부하고 싶다면 
iOS 8 Tutorials와 WatchKit by Tutorials를 참고하자.

Next?

iOS 8은 새로운 수많은 기능들을 제공한다. 원문에서는 더 공부할 수 있도록 링크들을 제공한다.
궁금하면 가서 보도록 하자.

레이웬더리치 블로그도 그렇고 스토리보드와 오토레이아웃은 점차 피할 수 없는 것처럼 보인다.
공부하도록 하자. 스위프트는 얼마나 실무에 다가왔는지 아직 잘 모르겠다.
조금 여유를 둬도 될 것이다.

다음에는 Supporting Multiple iOS Versions and Devices 이걸 훑어보면 좋을 것 같다.