Things take time

[SWIFT] Custom Scheme, 스키마를 이용한 앱 호출하기(외부 앱 열기) 본문

iOS (기능)

[SWIFT] Custom Scheme, 스키마를 이용한 앱 호출하기(외부 앱 열기)

겸손할 겸 2017. 7. 13. 17:46

[스키마를 이용한 앱 호출]

 

안드로이드의 경우, 매니페스트의 인텐트 필터를 이용하여 해당 필터링의 <data>~</data>를 통해 스키마를 등록하고 웹이나 외부 Uri값을 통해 앱의 특정 액티비티를 호출할 수 있었다. 이는 iOS에도 지원하는 부분이기 때문에 그 사용법을 정리한다. 단, iOS는 특정 액티비티, 뷰 컨트롤러를 여는 개념이 아니다. 뷰 컨트롤러가 아니라 앱 자체를 여는 것이라는 것을 염두하자. 이게 가장 중요하다.

 

 

[info.plist]

 

설정값을 저장하는 plist파일을 수정해야한다.

 

 

여기서 밑의 URL Types()를 보면 된다. 

Identifier부분에는 패키지명을 넣어주고, URL Schemes부분에는 원하는 스키마 명을 입력한다. 안드로이드의 경우 스키마 이름과 호스트 이름을 각각 지정하여 '스키마://호스트?파라미터' 형식이었지만, iOS는 호스트네임이 빠져서 '스키마://?파라미터' 로 보내면 된다.

 

[간단 앱 실행 실습]

 

 

 

간단히 처음 생성된 뷰 컨트롤러와, 스토리보드에는 텍스트 필드 하나만 써주고 연결해줬다.

 

 

처음 화면은 위와 같고

 

 

시뮬레이터에서 홈버튼 이동하여, 사파리를 키고 위의 스키마 주소대로 입력하면

 

 

스키마를 오픈할 것인지 묻는다. 여기서 Open을 누르면, 해당 스키마 주소로 세팅된 앱이 실행되게 된다.

 

 

[응용]

 

이제 특정 스키마 값을 갖고있는 앱을 실행시키는 것은 이해했을 것이다. 이것을 응용해서 스키마를 통해 앱으로 들어올때.. 예를 들어, swift example://?abc=def라는 문구로 들어왔을 때의 처리다.

 

즉, 파라미터를 처리하는 방식인데 안드로이드의 경우, 실행되는 액티비티에서 getIntent()를 통해 값을 처리하지만.. 처음에 설명한 것처럼 iOS는 특정 뷰 컨트롤러(안드로이드의 액티비티 개념)를 여는 것이 아니라, 앱 자체를 열기 때문에.. 처리하는 위치가 뷰 컨트롤러의 클래스가 아니라 AppDelegate.swift라는 앱 생성 시 기본으로 제공되는 클래스에서 처리한다.

 

그러므로 AppDelegate.swift에서 데이터를 받고, 뷰 컨트롤러의 변수 값을 지정하거나, 함수를 호출하는 방법으로 응용하면 되겠다.

이 작업을 위해서는 AppDelegate.swift에서 UIApplicationDelegate안에 적혀있는 application함수 하나를 오버라이드해야한다.

    @available(iOS 9.0, *)
    public func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
        
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let viewController = appDelegate.window?.rootViewController as! ViewController
        
        let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)
        let items = urlComponents?.queryItems
        
        viewController.title = items?.first?.name
        viewController.text.text = items?.first?.value
        
        return true
    }

이 함수는 어플리케이션이 URL을 통해 오픈되었을 때 호출되는 함수이다. 즉 외부 스키마를 통해 들어온 경우가 해당된다.

여기서 appDelegate와 viewController는 앱이 오픈되고 먼저 켜지는 뷰 컨트롤러(여기서는 기본 예제이기에 as! ViewContoller로 했지만, 다른 이름을 가진 뷰 컨트롤러가 처음 시작 뷰라면 변경해줘야한다)다.

 

중요한 것은 urlComponent와 items라는 것이다. 말 그대로 파라미터를 받기 위한 값이다. 이 값들을 받아 뷰컨트롤러의 타이틀 값과 처음 생성한 텍스트필드의 값을 변경할 수 있다. name은 파라미터의 키 값을, value는 파라미터의 밸류 값을 의미한다.

 

 

[실습]

 

앱을 다시 실행하고 swiftexamples://abc=def 를 사파리에서 열어보면

 

 

 

텍스트필드의 값이 def로 변경된 것을 확인할 수 있다. 네비게이션 컨트롤러나 다른 것을 사용하지 않아서 title이 변경된 것은 볼 수 없다. 어쨌든 해당 뷰 컨트롤러의 컴포넌트를 접근할 수 있다는 것이 중요한 것이다.

 

 

[추가]

 

앱에서 다른 앱을 열 때!

 

한가지 짚고 넘어가야할 것이 있다.

 

Info.plist에있는

URL Types는 외부의 앱(사파리를 포함한 기본앱, 혹은 다른 개발자가 만든 커스텀 앱)에서 내 앱을 실행시킬수 있도록 세팅하는 것이다.

그럼 반대로, 외부의 앱에서는 어떻게 해야할까.

    @IBAction func openScheme(_ sender: UIButton) {
        guard let schemeURL = URL(string: "custom://") else{
            return
        }
        
        if UIApplication.shared.canOpenURL(schemeURL){
            print(schemeURL)
            UIApplication.shared.open(schemeURL, options: [:], completionHandler: {
                (bool) -> Void in
                print(bool)
            })
        }
    }

A라는 앱에서는 URL Types에 URL identifier를 패키지명으로 Schemes값을 custom으로 했다고 가정한다.

그리고 B라는 앱에서는 위의 소스를 사용하여 A라는 앱을 실행시킬 것이다.

 

이렇게 코드를 돌리면, 이 스키마의 값(custom)이 등록되지 않았다는 에러메시지가 출력된다.

이럴때 B의 Info.plist에는 아래처럼 Quries Schemes값이 등록되있어야한다.

 

 

 

 

즉 A, B라는 두개의 앱에서 서로의 앱을 열게하려면(데이터를 기본적으로 주고받는 거라면)

 

앱을 열게되는 대상이 되는 앱은 URL Types를, 앱을 여는 주체가 되는 앱은 LSApplicationQueiresSchemes의 값에 URL Types에 등록된 name값을 넣어야한다.

서로가 모두 다 대상이면서 주체가된다면 각자의 앱에 URL Types와 LSApplicationQuriesSchemes가 등록되어있어야 한다.

 

이 예제를 바탕으로 카카오 링크나, 밴드처럼 공유하기를 사용하려면 LSApplicationQuriesSchemes에 값을 등록했던 것을 연관지어 생각하면 이해하기 쉬울 것이다. 그리고 카카오톡이나 밴드 앱 내부 plist에는 우리가 직접 보지 않아도 URL Types값이 등록되어 있을 것이란 것도 알 수 있다.