기타 기술들(Unity 관련)

갤럭시 워치 앱 개발 관련 내용

Dean83 2022. 3. 24. 22:39


1. 개요
    - 심박동 수와 스트레스 지수 표시를 위한 생체 정보 수집 필요
    - 생체 정보 수집을 위해 겔럭시 워치를 사용하여 생체정보를 수집 -> 안드로이드 기기에 전달 해주어야 함
    - 정보전달을 위해, 겔럭시 워치용 앱 (타이젠 기반)을 개발해야 하며, 안드로이드 앱 또한 개발해야 함.
       => 안드로이드 SDK 버전호환이 중요할것으로 보임. (STT 안드로이드 모듈과의 호환)
    
2. 갤럭시 워치 제품 정보 (제품 상세정보가 삼성페이지게 없음. 링크 연결이 안됨)
    * 갤럭시 워치 시리즈가 최신 제품

    - 갤럭시 기어 S3
       - 스트레스 지수 표시 - 삼성 헬스 앱에서 별도로 계산하여 표시하는듯 함
       - 심박수 측정
       - 운영체제 : 타이젠 4.0

    - 갤럭시 기어 Fit2 Pro
       - 심박수 측정
       - 스트레스 지수 표시 - 삼성 헬스 앱에서 별도로 계산하여 표시하는듯 함
       - 운영체제 : 타이젠 2.3

    - 갤럭시 워치 액티브2
      - 스트레스 지수 표시 - 삼성 헬스 앱에서 별도로 계산하여 표시하는듯 함
      - 심박수 측정
      - 운영체제 : 타이젠 4.0

    - 갤럭시 워치
       - 스트레스 지수 표시 - 삼성 헬스 앱에서 별도로 계산하여 표시하는듯 함
       - 심박수 측정
       - 운영체제 : 타이젠 4.0

    - 갤럭시 핏
      - 심박수 체크
      - 스트레스 체크 (안드로이드 앱으로 전달 가능한 여부는 아직 모름)
      - 운영체제 : freeRTOS 로, 외부 앱 개발을 지원치 않는듯함.

3. 타이젠
    - 모바일, 웨어러블, TV, 냉장고 등 삼성, 인텔, 리눅스에서 합작하여 만든 OS
    - 리눅스 커널을 사용하는 오픈소스 프로젝트로, 실제 사용처는 많지 않음
    - 바다 OS를 대체함
    - 안드로이드 apk파일을 실행 할 수 없음. (단, 오픈 모바일에서 ACL을 통해 타이젠 앱으로 변환가능)
     
    - 개발 : C 또는 C++의 네이티브 언어 개발 및 HTML5를 통한 웹개발 가능
                - C++이 가능하긴하나, OOP 기반이 아니라 C와 다를바가 없음. 메인은 C
                - Garbage Collection이 되지않아, 개발자가 일일히 해주어야 함.
                * 타이젠 3.0 이상부터는 C#을 통한 개발 가능 (자마린 형태)
                * 비쥬얼 스튜디오 개발시, debug breakpoint 동작 안함


                * 중요 : 타이젠 , 안드로이드 둘다 동일한 service profile을 가지고 있어야 함. (6.1, 7.2 참조)

    - 툴 : 비쥬얼 스튜디오 타이젠 익스텐션 및 자마린 기반 앱 개발 환경 가능
    - 타이젠 스튜디오 : 이클립스 기반으로, 윈도우, 리눅스, Mac에서 앱개발 가능
       - 이클립스 기반이라 자바 환경 구축해야 하나, Java 언어랑은 상관이 없고 사용할 수 없음.

4. 비쥬얼 스튜디오 타이젠 익스텐션
    - 타이젠 3 이상부터 지원하며 C#으로 개발 가능
    - 최신버전의 JDK 필요 (64bit지원)
    - Visual Studio Marketplace 이동 -> Tizen Extension 설치
      -> 도구 -> 확장 및 업데이트 -> 온라인 -> Visual Studio Marketplace -> 검색을 통한 설치
    - 설치 후 도구 -> Tizen -> Tizen Package Manager 실행 -> Install new Tizen SDK클릭하여 SDK 설치 
       -> 환경에 맞는 항목 추가 설치 (wearable 관련 sdk등)
    - 환경설정 추가
       -> 제어판 -> 시스템 -> 고급 시스템 설정 -> 환경 변수 클릭
       -> 시스템 변수 -> 새로만들기 -> 변수 이름에 CLASSPATH 입력 -> 변수 값에 %classpath%;, 입력
       -> 시스템 변수 -> 새로만들기 -> 변수 이름에 JAVA_HOME 입력 -> 변수 값에 실제 java sdk 설치 위치 입력 (예 : C:\Program Files\Java\jdk1.8.0_171)
       -> 시스템 변수 -> 리스트 에서 Path 선택 -> 편집 선택 -> 새로 만들기 선택 -> %JAVA_HOME%\bin 입력 후 확인

    - 애뮬레이터 실행
       - Cmos 에서 cpu -> 가상화 옵션 켜야 함 (Virtual Tech)(각 메인보드별 상이 하기때문에, 자체 검색 필요)
       - Hyper-V 가 꺼 있어야 함. 
          - 시작 -> 프로그램 및 기능 -> 윈도우 기능 켜기/끄기 -> Hyper-V 체크 해제
       - 비쥬얼 스튜디오 -> 도구 -> Tizen -> Tizen Enulator Manager 실행
       - 에뮬레이터 선택 -> Edit -> HW Support -> CPU VT, GPU 모두 On 으로 설정
       - 에뮬레이터 요구사항
          

5. 인증서 생성
     - https://developer.samsung.com/galaxy-watch-develop/getting-certificates/create.html 참조
     - 인증서에는 범용, 삼성 인증서가 따로 있으며, 삼성 기기에 설치를 위해선 삼성 인증서 발급 받아야 함. 
        * 비주얼 스튜디오 -> 도구 -> Tizen -> Tizen Package Manager -> Extension SDK에 Samsung 관련된 SDK 설치
     - 비주얼 스튜디오 -> 도구 -> Tizen -> Tizen Certificate Manager 실행
        -> Ceritificate Profile 추가 -> 우측 Samsung 클릭 -> Mobile/Wearable 선택 후 다음 클릭
        -> Create a new certificate profile 선택 후, 명칭 입력 후 다음 클릭
        -> Create a new author certificate 선택 후 다음 클릭 
        -> Author Name, Password 입력 후 다음 클릭 
        -> 삼성 계정에 로그인 혹은 회원 가입 후 로그인 
        -> backup path 설정 후 다음 클릭
        -> Create a new distributor certificate 선택 후 다음 클릭
        -> 하단 Add individual DUIDs 에 값 입력 후 다음 클릭
        -> 비주얼 스튜디오 -> 도구 -> 옵션 -> Tizen -> Certification 클릭
        -> Sing the .TPK file using the following option 에 체크
        -> Use profile of Tizen Certificate Manager 선택
        -> Profile -> Profile Path 확인 및 Profile 에, 위에서 추가한 active된 samsung certificate를 선택

        * DUID는 기기 고유 정보로서, PC와 연결하면 자동으로 등록됨. 이를 등록해야만 기기에 앱 설치가 가능함. 
        * 인증서 생성기 실행 불가시, 설치경로로 이동하여 eclipse.exe 실행
          

6. 갤럭시 워치 프로젝트 생성
     - 비주얼슈트디오 -> 파일 -> 새로만들기 -> 프로젝트 -> Visual C# -> Tizen 4.0 선택
     - Tizen Watchface App 혹은 Black App 등 원하는 항목 선택
     - 코드 개발은 Provider (서버 개념) 과 Consumer (클라이언트 개념) 으로 나뉨.
     - (삼성 sap api 문서) https://img-developer.samsung.com/onlinedocs/gear/Tizen_SAP/namespaceSamsung_1_1Sap.html  
     - 솔루션 탐색기 -> 마우스 우클릭 -> Nuget 패키지 관리 -> 찾아보기 -> samsung.sap 설치 (프로젝트 생성시 마다 해줘야함)

        * 겔럭시 워치앱 또는 watchface 로 프로젝트를 개발하면 안되며, 반드시 widget으로 개발할것. 
            => 워치에서 개발중인 어플을 직접 실행하려면 widget으로 개발해야함. 6.8. 참조

     6.1. Profile 추가
            - 안드로이드와 통신을 위해 반드시 필요
            - /res/xml 폴더 (없으면 생성) 에 accessoryservices.xml 파일 생성 
              => /res/xml 폴더 마우스 우클릭 -> 추가 -> 새항목 -> 데이터 -> xml 파일 선택 후 파일명 입력 -> 추가
            - 아래의 xml 내용 추가. application 명칭 변경 칠요하며, service profile id 는 unique한 값으로 입력해야함.
               => tizen-manifest.xml -> overview 에 기록되어 있는 application id와 같은것으로 입력. 단 '.' 을 '/'로 변경
               => /로 시작하며, 0~9까지의 숫자, a ~ z 까지 영문자와 _가 허용되며, 구분자로 / 를 사용함. 최대길이 30자

<?xml version="1.0" encoding="utf-8"?>
<resources>
<application name="MyApplication">
<serviceProfile id="/org/example/myapp/my_message" name="MyMessage"
                role="consumer"  version="1.0">
<supportedTransports>
<transport type="TRANSPORT_BT"/>
<transport type="TRANSPORT_WIFI"/>
</supportedTransports>
<serviceChannel id="110" dataRate="low" priority="low"
                reliability="enable">
</serviceChannel>
            <supportedFeatures>
              <feature type="message" />
            </supportedFeatures>
</serviceProfile>
</application>
</resources>

            - tizen-manifest.xml 더블 클릭 -> advanced 클릭 -> add 클릭
            - key 에  accessory-services-location 입력, value에 해당 파일 위치 (/res/xml/accessoryservices.xml)입력

     6.2. Previlege 추가
            - tizen-manifest.xml 더블 클릭 -> previleges 클릭 -> add 클릭
            - custom previlige 선택 후 http://developer.samsung.com/tizen/privilege/accessoryprotocol 입력
            - tizen-manifest.xml 더블 클릭 -> previleges 클릭 -> add 클릭 -> platform defined 에서 원하는 항목 선택 후 추가     
               * Display On을 위해  다음을 추가 : <privilege>http://tizen.org/privilege/display</privilege>
                                                                  <privilege>http://tizen.org/privilege/systemsettings</privilege>

      6.3. api 사용 using
              - using Samsung.Sap; 추가 (삼성에서 제공하는 별도의 api)   
              - 패키지가 없을경우, 비주얼 스튜디오 -> 도구 -> Nuget Package 관리자 -> 솔루션용 Nuget 패키지 관리 -> 찾아보기 -> samsung 검색 
                -> samsung sap 설치 (매 프로젝트 마다 설치 필요)

      6.4. 센서 값 사용
              - using Tizen.Sensor; 추가
              - tizen-manifest.xml 더블 클릭 -> previleges 클릭 -> add 클릭 -> healthinfo 추가 필요
              - Tizen.Sensor를 보면, 각 센서 클래스가 있음.
              - var sensor = new 센서클래스명(); 으로 메모리 할당   
              * 앱설치시, manifest에서 권한을 줬음에도 불구하고, 설정 -> 앱 ->권한 -> 설치된 앱 선택 -> 센서 권한 허용해야함         
              
              6.4.1. 센서 이벤트
                        - sensor변수명.DataUpdated 이벤트를 통해 데이터 값을 받을 수 있음. 
                        - 이벤트 인자값은 센서마다 다른듯 함. 
                        - sensor변수명.Start()를 통해 센서 시작
                        - sensor변수명.Interval 에 값을 배정함으로서 주기를 설정할 수 있음. (miliseconds)
                           => 1초가 적절한 주기로 생각됨. 주기 시간이 짦을경우 app crash 발생함.
                        - sensor변수명.PausePolicy에 SensorPausePolicy enum값 배정으로 일시정지 정책 설정 가능
                           => 예 : SensorPausePolicy.DisplayOff. None 설정시 계속 동작
                           => None으로 설정해야함!!
                        - sensor변수명.Stop()을 통해 센서 중지. 이벤트 추가 한것도 제거해주어야 함. Dispose 호출도 필요.
                        * 심박수 이벤트의 경우 이벤트 인자값이 int 임. (심박수)  

              6.4.2. 센서 종류
                        - Tizen 기준이므로, 실제 기기들이 다 지원하지는 않음. 각 기기 스펙별로 확인 필요
                        - try catch 구현, catch 문에 NotSupportedException 수신될 경우, 지원되지 않는 센서임. 
                        - https://docs.tizen.org/application/dotnet/guides/location-sensors/device-sensors 에 지원 전체 센서 목록 있음

              6.4.3. 디스플레이 강제 on
                         - display를 항상 강제로 on 할 필요가 있을경우 사용
                         - DllImport를 통해 DevicePowerRequestLock 함수를 호출함.
                         - 6.2. 권한 참조하여 추가해야함. 
                            - 1번째 인자값 
                               - 1 : cpu 전원 off 막음
                               - 2 : display normal
                               - 3 : display dim
                            - 함수 리턴값
                               => 0 : 정상
                               => -22 : invalid parameter
                               => -13 : permission denied
                               => -0x01140000 또는 0x01 : operation failed

// Main 함수가 있는  프로그램 진입점 클래스에 다음을 추가 

[DllImport("libcapi-system-device.so.0", EntryPoint = "device_power_request_lock", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int DevicePowerRequestLock(int type, int timeout_ms);

[DllImport("libcapi-system-device.so.0", EntryPoint = "device_power_release_lock", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int DevicePowerReleaseLock(int type);

//main 함수에 다음을 추가
// ret 값에 따라 오류 판별

int ret = DevicePowerRequestLock(1, 0);


 

      6.5. 샘플 프로젝트
              - 비주얼슈트디오 -> 파일 -> 새로만들기 -> 프로젝트 -> Visual C# -> Tizen 4.0 선택 으로 프로젝트 생성시,

              6.5.1. 구조
                        - 프로젝트명.cs : 메인 진입점
                           - 기본 이벤트 함수들이 연결되어 있음.
                        - xxxx.xaml : UI 설정 xaml 파일
                        - xxxx.xaml.cs : xaml 과 연동되는 코드
                        - xxxViewModel.cs : UI와 연결되는 ViewModel. binding 연결 등 담당함. PropertyChanged 이벤트 구현되어 있음.
                         
              6.5.2. xaml 에 바인딩 예
                        - Text="{Binding Path=ViewModel에 있는 변수명, Mode=OneWay, UpdateSourceEventName=PropertyChanged}"
                        - ViewModel에 있는 변수명은 Public으로 선언되어 있어야 하며, Get, Set이 있어야 하고, Set의 경우 OnPropertyChanged 호출해주어야 UI 업데이트가 잘됨
                        - 예 :

        public string _hr;
        public string HR
        {
            get
            {
                return _hr;
            }
            set
            {
                _hr = value;
                OnPropertyChanged("HR");
            }
        }

      6.6. 안드로이드 기기 연결
              - 삼성 API를 사용하여 안드로이드 기기와 연결. 안드로이드 기기측에서도 삼성 API를 사용하는 어플리케이션 개발이 이루어 져야 함. 
              - 6.1, 6.2, 6.3 을 수행 한 후에 진행. 
              - 첨부파일에 첨부된 SAccessoryService_Emul.apk 를 휴대폰에 설치하여 연결테스트 진행 가능 
                 - 샘플 apk를 이용한 연결 참조 : https://developer.samsung.com/galaxy-watch-develop/creating-your-first-app/net-companion/galaxy-watch-emulator.html
                          

    //consumer

    private async void Connect()
{
try
{
            //getagent의 인자값 : accesoryservice.xml 에 적어놓은 serviceprofile id
            //tizen-manifest.xml의 application id = accesoryservice.xml 의 serviceprofile id와 동일
Agent = await Agent.GetAgent(Samsung.Sap.Service.Profiles.First());
var peers = await Agent.FindPeers();
if (peers.Count() > 0)
{
var peer = peers.First();
Connection = peer.Connection;
Connection.DataReceived -= Connection_DataReceived;
Connection.DataReceived += Connection_DataReceived;
                Connection.StatusChanged -= Connection_StatusChanged;
                Connection.StatusChanged += Connection_StatusChanged;
await Connection.Open();
}
else
{
//연결 대상 찾지못함
}
}
catch (Exception ex)
{
//오류발생
}
}

    private void Connection_StatusChanged(object sender, ConnectionStatusEventArgs e)
    {
         if(e.Reason != ConnectionStatus.Connected)
         {
             Tizen.Log.Debug("tag", "disconnected");
         }
         else
         {
             Tizen.Log.Debug("tag", "connected");
         }
    }

    private void Connection_DataReceived(object sender, DataReceivedEventArgs e)
{
//메세지 수신부
}

    private async void SendMessage(Peer peer, string message)
    {
        if (peer == null || peer.Status != PeerStatus.Found)
            return;

        await peer.SendMessage(Encoding.UTF8.GetBytes(message));
    }

    private void CloseConnection(Peer peer)
    {
        peer.Connection.Close();
    }

      6.7. 워치에 빌드앱 설치 (PC에서 빌드 - 기기에 설치)
              - 참조 : https://developer.samsung.com/galaxy-watch-develop/testing-your-app-on-galaxy-watch.html
              - wifi를 통해 연결 필요. 

              6.7.1. PC 세팅
                        - wifi 동글 필요 혹은 동일 ap에 접속 필요.
                        - 제어판 -> Windows Defender 방화벽 -> 고급 설정 -> 인바운드 규칙 -> 새 규칙 ->  포트
                          -> 다음 클릭 -> TCP 선택 -> 특정 로컬 포트에 26101 입력 -> 연결 허용 선택 -> 이름 입력 후 확인
                          * UDP에서도 동일한 세팅 필요.
                          * 제어판 -> Windows Defender 방화벽 -> 고급 설정 -> 아웃바운드 규칙 에도 동일한 설정 필요

              6.7.2. 겔럭시 워치 세팅
                        - 워치 기기 -> 세팅 -> 워치 정보 -> 디버깅 켬
                        - 워치 기기 -> 세팅 -> 워치정보 -> 소프트웨어 -> 소프트웨어 버전을 5번 터치 시 개발자 옵션 켜짐
                        - PC와 동일 네트워크 혹은 PC에 wifi 동글 동작 -> 워치에서 해당 wifi 접속
                        - 비주얼 스튜디오 -> 도구 -> Tizen -> Tizen Device Manager 실행 -> 우측 3개의 아이콘중 가운데의 Remote Device Manager 실행
                           -> 스캔 버튼 클릭 -> 연결 버튼 클릭
                        - 비주얼 스튜디오 -> 도구 -> Tizen -> sdb command prompt 실행
                        - sdb devices 로 연결됨을 확인
                        - sdb connect ip주소 입력시 is already connected 표시됨을 확인
                           * 연결이 안될경우 워치 재부팅, 설정된 remote device 에서 목록 삭제 후 재 검색 등 수행
                           * connect 시 워치에 허용 메세지창이 뜨는데, 수락해주어야 함. 가끔 안뜰때가 있는데, 재부팅, 재접속 후 재 시도 등 해볼것

              6.7.3. 앱 설치
                        - 비주얼 스튜디오 -> 도구 -> Tizen -> sdb command prompt 실행
                        - sdb install 설치파일  (tpk 확장자를 가짐)
                          * sdb 는 tizen 스튜디오 -> tools 에 있음. 이 위치에 tpk 파일을 위치해놓고 실행
                          * 계정 정보에 certificate 가 되어 있는지 확인할것. 5. 인증서 생성 참조  

      6.8. Widget
              - 워치에 설치한 어플리케이션을 직접 실행할 방법을 찾지 못함. 
              - Widget 어플리케이션 만이 워치에서 개발중인 앱을 단독 실행 가능함. 
              
               6.8.1. 필수구성
                         - 프로젝트 마우스 우클릭 -> nuget package 관리 -> 찾아보기 -> Tizen.Wearable.CircularUI 검색 후 설치 
                         - 프로젝트 마우스 우클릭 -> 추가 -> 새항목 -> 사용자 정의 컨트롤 (WPF) 선택 후 추가 (system 참조 오류 발생하나, 무시)

                         6.8.1.1. 기본 프로젝트 구성파일
                                      - ViewModel.cs 파일 (필수는 아님 MVVM 패턴에 사용되는 부분)
                                      - xaml 파일 2개
                                        => 프로그램 메인진입점 UI 페이지
                                        => 실제 UI 개발 페이지
                                      - 각 xaml과 연결되는 xaml.cs 파일 2개
                                      - 프로젝트명.cs 파일
                                         => 프로그램 최초 진입점
                                      - tizen-manifest.xml 수정 필수

                         6.8.1.2. 메인 진입점 xaml 
                                      - 빈 껍데기만 있는 형태
                                      - 예 : 

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TizenWatchfaceApp2.UserControl1">
</Application>

                         6.8.1.3. 메인 진입점 xaml.cs
                                      - 실제 UI가 표시되는 클래스를 메인페이지에 연결
                                      - 예 : 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TizenWatchfaceApp2
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class UserControl1 : Application
    {
        public UserControl1(ClockViewModel viewModel)
        {
            InitializeComponent();
            MainPage = new TextWatchApplication(viewModel);
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

                         6.8.1.4. 실제 UI xaml
                                      - 실제 UI가 표시되는 페이지
                                      - Tizen CircleUI를 활용함. 따라서 해당 네임스페이스 추가해야함
                                      - 기본 구조 : 

<?xml version="1.0" encoding="utf-8" ?>
<c:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
              xmlns:c="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=Tizen.Wearable.CircularUI.Forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="네임스페이스.연동클래스명">
    <c:CirclePage.Content>
        <AbsoluteLayout>
            <ContentView AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="All">
                <StackLayout>

                    <!-- 이곳에 UI 개발 -->

                </StackLayout>
            </ContentView>
        </AbsoluteLayout>
    </c:CirclePage.Content>
</c:CirclePage>

                         6.8.1.5. 실제 UI xaml.cs
                                      - 실제 UI가 표시되는 페이지와 연동하여 동작 코드 개발. 기존 wpf와 크게 다르지 않음. 

                         6.8.1.6. 프로그램 메인 진입점.cs (프로젝트명.cs)
                                      - 실제 프로그램 메인 진입점으로, 어플리케이션 실행을 담당
                                      - 6.8.1.2. 와 6.8.1.3. 에서 기술한 메인UI를 실행시킴 
                                      - FormsWidgetBase 상속받은 클래스와 FormsWidgetApplication 상속받은 클래스로 구성됨.
                                      - 예 : 

using System;
using System.Timers;
using Tizen.Applications;
using Tizen.Wearable.CircularUI.Forms.Renderer;
using Tizen.Wearable.CircularUI.Forms.Renderer.Watchface;
using Tizen.Wearable.CircularUI.Forms.Renderer.Widget;
using Xamarin.Forms;

namespace TizenWatchfaceApp2
{
    class 클래스명_A: FormsWidgetBase
    {

        public override void OnCreate(Bundle content, int w, int h)
        {
           
            base.OnCreate(content, w, h);
            var 메인진입점 변수 = new 메인진입점클래스명();
            LoadApplication(메인진입점 변수);
        }
    }

    class 클래스명_B: FormsWidgetApplication
    {

        public 클래스명_B(Type type) : base(type)
        {
        }

        static void Main(string[] args)
        {
            var app = new 클래스명_B(typeof(클래스명_A));
            Forms.Init(app);
            FormsCircularUI.Init();
            app.Run(args);
        }
    }
}
   

                         6.8.1.7. tizen-manifest.xml 수정
                                      - 해당파일 선택 -> 마우스 우클릭 -> 다른 프로그램으로 열기 -> xml(텍스트) 자동편집기 선택 후 확인 클릭
                                      - <manifest> 하위에 <xxxx-application>을 <widget-application> 태그로 변경해야함.  
                                         -> 어트리뷰트 exec="프로젝트명.dll"  update-period="0" 추가
                                      - <widget-application> 하위에 <support-size preview="파일명.png">2x2</support-size> 추가
                                      - <manifest> 하위에 <background-category value="sensor" /> 추가
                                      - 예 : 

<?xml version="1.0" encoding="utf-8"?>
<manifest package="org.tizen.example.TizenWatchfaceApp2" version="1.0.0" api-version="4" xmlns="http://tizen.org/ns/packages">
    <author>park</author>
    <profile name="wearable" />
    <background-category value="sensor" />
  <widget-application appid="org.tizen.example.TizenWatchfaceApp2" exec="TizenWatchfaceApp2.dll"  update-period="0" type="dotnet">
    <label>TizenWatchfaceApp2</label>
    <icon>TizenWatchfaceApp2.png</icon>
    <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
    <support-size preview="TizenWatchfaceApp2.png">2x2</support-size>
    <metadata key="accessory-services-location" value="/res/xml/accessoryservices.xml" />
    <splash-screens />
  </widget-application>
    <shortcut-list />
    <privileges>
        <privilege>http://tizen.org/privilege/alarm.set</privilege>
        <privilege>http://developer.samsung.com/tizen/privilege/accessoryprotocol</privilege>
        <privilege>http://tizen.org/privilege/content.write</privilege>
        <privilege>http://tizen.org/privilege/bluetooth</privilege>
        <privilege>http://tizen.org/privilege/datasharing</privilege>
        <privilege>http://tizen.org/privilege/healthinfo</privilege>
        <privilege>http://tizen.org/privilege/network.get</privilege>
        <privilege>http://tizen.org/privilege/internet</privilege>
        <privilege>http://tizen.org/privilege/network.profile</privilege>
        <privilege>http://tizen.org/privilege/network.set</privilege>
        <privilege>http://tizen.org/privilege/wifidirect</privilege>
        <privilege>http://tizen.org/privilege/widget.viewer</privilege>
    </privileges>
    <provides-appdefined-privileges />
</manifest>



      6.9. 유용한 shell 명령어
              - 비주얼 스튜디오 -> 도구 -> Tizen -> Tizen Device Manager 실행
              - 현재 동작중인 장비 선택 -> 마우스 우클릭 -> shell prompt 로 각종 명령어를 입력할 수 있음. 
                 - pkginfo --listpkg : 설치된 패키지목록을 보여줌. uninstall 할때 패키지명 확인을 위해 필요.


7. 안드로이드 앱 (워치와 통신)
     - https://developer.samsung.com/galaxy-watch-develop/techdoc/how-to-use-samsung-accessory-sdk.html 참조
     - (샘플 코드 및 menifest 세팅) https://developer.samsung.com/galaxy-watch-develop/creating-your-first-app/net-companion/use-accessory.html
     - 첨부파일 중, AccessorySDK 다운로드 필요
     - 코드 개발은 Provider (서버 개념) 과 Consumer (클라이언트 개념) 으로 나뉨.
     - 첨부파일인 ProgrammingGuide_Accessory pdf 문서 참조
     - 안드로이드 4.4.2 이상 필요하며, 2개의 jar파일 포함해야함.
     - accessory-v2.3.0.jar, sdk-v1.0.0.jar     

       7.1. AndroidManifest.xml 수정
               7.1.1. Permission

<uses-permission
android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURV
EY"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="com.samsung.accessory.permission.ACCESSORY_FRAMEWORK"/>

               7.1.2. 그외

<application>
    <service android:name="com.example.myapplication.ProviderService" />
    <meta-data
android:name="AccessoryServicesLocation"
android:value="/res/xml/accessoryservices.xml" /> <!-- 실제 accessoryservices.xml 위치-->
<receiver android:name="com.samsung.android.sdk.accessory.RegisterUponInstallReceiver">
<intent-filter>
<action android:name="com.samsung.accessory.action.REGISTER_AGENT" />
</intent-filter>
</receiver>
<receiver android:name="com.samsung.android.sdk.accessory.ServiceConnectionIndicationBroadcastReceiver">
<intent-filter>
<action android:name="com.samsung.accessory.action.SERVICE_CONNECTION_REQUESTED" />
</intent-filter>
</receiver>
</application>

       7.2. accessoryservices.xml 추가
               - res/xml 에 추가 (7.1.2. 의 <meta-data> 태그 -> android:value 와 연관됨)

<!-- accessoryservices.xml 예시 -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<application name="MyApplication">
<serviceProfile
id="/org/example/myapp/my_message"
name="myapplication"
role="provider"
serviceImpl="com.example.myapplication.ProviderService"
version="1.0"
serviceLimit="ANY"
serviceTimeout="10">
<supportedTransports>
<transport type="TRANSPORT_BT" />
<transport type="TRANSPORT_WIFI" />
</supportedTransports>
            <supportedFeatures>
                <feature type="message" />
            </supportedFeatures>
<serviceChannel
id="110"
dataRate="low"
priority="low"
reliability= "enable"/>
</serviceProfile>
</application>
</resources>

<!-- application name은 안드로이드 appname을 보통 사용함 -->
<!-- serviceProfile name, id는 아무거나 적어도 되는듯함. id의 경우 watch app의 규정과 동일 -->
<!-- serviceProfile의 role 에 provider, consumer 설정을 함 -->

       7.3. Android app 코드
               7.3.1. Import
                         - 기본으로, import com.samsung.android.sdk.accessory.*; 추가.
                         - 파일전송 사용시, import com.samsung.android.sdk.accessoryfiletransfer.*;
                                                  import com.samsung.android.sdk.accessoryfiletransfer.SAFileTransfer.*;
                           추가

              7.3.2. 코드
 

class HelloAccessoryProvider extends SAAgent
{
    ...
     void onCreate() {
            Create SA;
            try
            {
                Initialize SA;
            }
            catch (Exception e)
            {
                // Error Handling
            }
        }
     void onStart() {

            // Find Peer Agent
            FindPeerAgent();
        }
     void onFindPeerAgentsResponse(SAPeerAgent []
        peerAgents, int result) {
            // Store found Peer Agent if success
            if (result == PEER_AGENT_FOUND)
            {
                for (SAPeerAgent peerAgent : peerAgents)
                    Cache(peerAgent);
            }
        }
     void onServiceConnectionRequested(SAPeerAgent peerAgent) {
            // Received service connection request from remote, decide whether to accept or to reject.
            Accept(peerAgent);
        }
     void onServiceConnectionResponse(SAPeerAgent peerAgent, SASocket socket, int result) {
            // if result is successful, cache socket for using on sending message
            Cache(socket);
        }
     class ServiceConnection extends SASocket
    {
     void onReceive(int channelId, byte[]
        data) {
            // Check received data
            Parse(data);
            // Create a worker thread and send message to Consumer
            Create WorkerThread(
            message = composeMessage();
            CachedSocket.Send(channel id, message);
     );
        }
     void onServiceConnectionLost(int errorCode) {
            // Reset cached peer agent and close service connection
            ResetCache();
            Close();
        }
     void onError(int channelId, String errorString, int error) {
            // Error handling
        }
    }
    ...
}

//consumer

class HelloAccessoryConsumer extends SAAgent
{
...
 void onCreate() {
        Create SA;
        try
        {
            Initialize SA;
        }
        catch (Exception e)
        {
            // Error Handling
        }
    }
 void onStart() {
        // Find Peer Agent
        FindPeerAgent();
    }
 void onFindPeerAgentsResponse(SAPeerAgent []
    peerAgents, int result) {
        // Store found Peer Agent if success
        if (result == PEER_AGENT_FOUND)
        {
            for (SAPeerAgent peerAgent : peerAgents)
            {
                Cache(peerAgent);
                RequestServiceConnection(peerAgent);
            }
        }
    }
 void onServiceConnectionResponse(SAPeerAgent peerAgent, SASocket socket, int result) {
        // if result is successful, cache socket for using on sending message
        Cache(socket);
        Create WorkerThread(
         try
                {
                    message = composeMessage();
                    Send(channel id, message);
                }
                catch (Exception e)
                {
                    // Error handling
                }
         );
            }
         class ServiceConnection extends SASocket
        {
         public void onReceive(int channelId, byte[] data)
        {
            // Check received data
            Parse(data);
            // Create a worker thread and show message to user
            Create WorkerThread(
            Show(message);
         );
        }
        void onServiceConnectionLost(int errorCode)
        {
            // Reset cached peer agent and close service connection
            ResetCache();
            Close();
        }
        void onError(int channelId, String errorString, int error)
        {
            // Error handling
        }
    }
...
}

       7.4. 빌드세팅
               - gradle 설정에서, compileSdkVersion 24로 설정, minSdkVersion은 21로 설정 (혹시 모를 stt 모듈과의 호환성)
                  그외 오류시, dependencies -> com.android.support:appcompat-v7:24.2.1 로 설정 후 빌드

       7.4.1. Gradle 설정 예





8. 로그
     - 기존에 사용하던 Console.Write 나, Debug.Write 는 동작하지 않음. 
     - Tizen.Log 클래스를 활용하여 로그 작성을 해야함. 
       - Tizen.Log.Debug, Info 등 여러 항목이 존재함. 
     - Tizen.Log.Debug의 경우, (string tag, string message )를 인자로 하여 작성 가능
     - 비주얼 스튜디오 -> 도구 -> Tizen -> Tizen Log Viewer 를 통해 확인 가능. 
        - 필터 기능을 통해 원하는 로그만 볼 수 있음 (예 : 태그명)
        - 비주얼 스튜디오 디버깅 모드 실행시에만 확인가능

999. 참조
        - 타이젠 개발 : http://preview.hanbit.co.kr/2764/sample_ebook.pdf
                             https://mintpot.synology.me:30000/issues/1309
                             https://cyberx.tistory.com/158
                             https://docs.tizen.org/application/dotnet/tutorials/overview

        - https://developer.samsung.com/galaxy-watch-develop
        - https://img-developer.samsung.com/onlinedocs/gear/Tizen_SAP/namespaceSamsung_1_1Sap.html