Windows Application Packaging Project를 이용해서 만든 Destktop Bridge app에서 UWP App과 interop하기.

최근 Visual Studio 15.4.1에 Windows Application Packaging Project 템플릿이 추가됐다.
이 템플릿을 이용하면 손쉽게 데스크탑 어플리케이션을 AppX로 패키징할 수 있다.
그 방법이 너무나 쉬우므로 자세한 설명은 달지 않는다. 링크 참조.
https://blogs.windows.com/buildingapps/2017/10/18/visual-studio-2017-update-4-makes-easy-modernize-desktop-application-make-store-ready/

그런데 github의 MS샘플도 그렇고 어디에도 이 템플릿을 사용했을때 uwp app과 interop하는 예제는 없다.

내가 원하는 샘플과 자료는 아래 링크의 내용이다.
https://docs.microsoft.com/en-us/windows/uwp/porting/desktop-to-uwp-extend

그런데 빌어먹을….이건 VS2017에 추가된 Windows Application Packaging Project 템플릿을 이용하는게 아니고 예전 데스크탑 브릿지 기술로 구현하는 얘기다.

하룻밤을 꼬박 새고 반나절을 날려서 Windows Application Packaging Project에 UWP App 프로젝트를 추가하고 데스크탑앱에서 uwp app을 부르는 방법을 찾아냈다.
빌어먹을 마이크로소프트. WTF. Fucking Microsoft…

위 링크의 자료를 기본으로 Windows Application Packaging Project 템플릿을 사용했을때 어떻게 UWP app을 같이 패키징하고 실행할 수 있는지 적어보겠다.

우선 Windows Application Packaging Project에 데스크탑앱 프로젝트를 추가했고 이걸로 빌드와 실행은 된다고 가정한다.
이 상태에서 UWP앱 프로젝트를 추가해야한다.
솔루션에 UWP앱 프로젝트를 하나 추가한다. 이걸로는 단지 같이 빌드를 할 뿐이지 같은 AppX패키징을 하지는 않는다.
솔루션 탐색기에서 Add Reference로 uwp app을 추가하려고 하면 에러를 뱉는다. 현재는 VS2017의 IDE로 UWP App reference로 추가할 수 없다.

xxxx.waaproj파일을 직접 열어서 추가하도록한다. 솔루션 탐색기에 보이는 Windows Application Packaging 프로젝트에서 오른쪽 버튼 눌러보면 보면 Edit xxxx.wapproj메뉴가 있다.
wapproj.PNG

add_reference_on_wapproj
이런식이다. 윗쪽이 데스크탑 앱으로, 이건 IDE를 통해서 이미 추가했을것이다. 아랫쪽에 UWP앱 프로젝트를 추가해준다.
이거 안해주고 단지 솔루션에 묶은걸로는 때려죽여도 같이 패키징 되지 않는다.

일단 여기까지 하면 빌드가 되고 같이 패키징까지는 된다.
실행하면 데스크탑앱이 실행된다.
이제 데스크탑앱에서 UWP앱을 불러야한다.
데스크탑앱에서 UWP앱은 어떻게 부르느냐 하면…

String ^str = ref new String(L"desktopbridgexamlui://");
Uri ^uri = ref new Uri(str + L"test");
Windows::System::Launcher::LaunchUriAsync(uri);

이런식으로 부른다.

desktopbridgexamlui이라는 내맘대로의 프로토콜을 정의했고 이 프로토콜 요청이 들어오면 어떤 앱(UWP앱)을 실행하라고 하는 설정을 Package.appxmanifest파일에 적어준다.

String^이나 Windows::System::Launcher::LaunchUriAsync::LaunchUriAsync()은 UWP API를 C++/CX코드로 사용하고 있는 것인데 데스크탑앱 프로젝트에서 기본적으로 C++/CX는 사용할 수 없다. 스샷찍기 귀찮다. 데스크탑앱에서 C++/CX와 UWP API를 사용하는 방법은 다음의 링크를 참고해주기 바란다.
https://blogs.windows.com/buildingapps/2017/01/25/calling-windows-10-apis-desktop-application/#q4fX6wa8pSz2jHL2.97

그럼 UWP앱 프로젝트를 추가하고 프로토콜을 정의해보자.
Windows Application Packaging 프로젝트쪽의 Package.appxmanifest파일을 열어서 다음과 같이 항목을 추가한다.

protocol.PNG

manifest 디자이너의 declaration항목에 보면 다음과 같이 표시된다.
protocol_manifest
내가 사용할 UWP앱의 실행파일이 XamlUI.exe고 Entry Point는 XamlUI.App이다. 따로 고치지 않았다면 이건 해당 UWP앱 프로젝트의 이름과 동일하다. 미심쩍으면 App.xaml파일을 열어보면 x:Class=”XamlUI.App” 이라는 식으로 Entry Point를 확인할 수 있다.

데스크탑앱쪽에서 Windows::System::Launcher::LaunchUriAsync::LaunchUriAsync()함수로 desktopbridgexamlui라는 프로토콜에 응답하는 앱을 실행해달라고 요청하면 함께 패키징된 XamlUI.exe를 실행되는 것이다.

여기까지 하면 어쨌든 XamlUI앱이 실행은된다. 하지만 어떤 xaml 페이지도 뜨지 않는다.

데스크탑앱의 요청을 받아 XalmUI::App인스턴스가 활성화됐을때 이벤트를 처리하기 위해서 추가적인 작업을 해야한다.

아마 기본적으로 앱에 OnLaunched()핸들러가 자동으로 코딩되어있을텐데 이건 쓸모가 없다.
OnActivated()핸들러를 추가로 코딩한다.

onactivate_h

onactivate_cpp

간단하게 데스크탑앱쪽에 아래와 같이 코딩한다.
String ^str = ref new String(L”desktopbridgexamlui://”); 에서 desktopbridgexamlui는 Package.appxmanifest쪽에 넣어준 프로토콜 이름을 넣으면 된다. 그 아래 Test로 넣은것은 주소로 전달하는 항목이다. UWP앱쪽에서 uri를 파싱해서 얻을 수 있다.

launch_from_Desktop

f5를 눌러서 실행해보면 데스크탑앱이 먼저 실행되고 곧 UWP앱이 실행된다. 브레이크 포인트를 찍어보면 OnActivated()핸들러에 브레이크 포인트를 찍어보면 데스크탑앱에서 전달한 uri도 확인할 수 있다.

run_app

빌드가 되고 실행이 되어도 패키지 만들려고 하면 에러가 날것이다. assets폴더가 겹친다고 한다. Windows Application Packaging프로젝트에서 기본으로 만든 assets폴더에 타일 이미지들이 들어있고 새로 추가한 UWP앱 프로젝트에의 assets폴더에도 타일 이미지들이 들어있다. 있다. 빌드하고 실행할땐 괜찮지만 최종적으로 패키지를 만들땐 충돌한다.
해결방법은 방법은 간단하다. Windows Application Packaging 프로젝트의 Assets 폴더의 타일이미지들을 다 지운다. 이렇게 하면 AppX는 같이 패키징한 UWP앱의 assets폴더의 이미지를 사용한다.

앱패키지를 만들고 나면 Windows App Certification kit로 테스트를 할거냐고 묻는다.
테스트를 하고 통과하면 다음과 같이 표시된다.
cerf_passed
OK. 바이너리만 놓고 볼때는 스토어에 올릴 준비가 됐다.

테스트로 설치하려면 패키지 폴더 안에 있는 인증서를 설치한다. Local Machine -> Trusted People에 설치하면 된다.

그리고 xxxx.appxbundle파일을 실행하면 앱이 설치된다.
install_package

내가 까먹을까봐 문서로 정리했다.

p.s : 데스크탑 브릿지 개발하시는 분들 교류좀 합시다요.


답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중