다음을 통해 공유


방법 가이드: Graph 알림과 통합(iOS)

Graph 알림을 사용하면 앱이 여러 디바이스에서 사용자를 대상으로 하는 알림을 보내고 관리할 수 있습니다.

iOS에 프로젝트 로마 클라이언트 쪽 SDK를 사용하면, 로그인된 사용자를 대상으로 하는 앱 서버에서 게시된 알림을 iOS 앱이 수신하도록 등록할 수 있습니다. SDK를 사용하면 앱 클라이언트가 새로 들어오는 알림 페이로드를 수신하고, 기존 알림의 상태를 관리하고, 알림 기록을 검색할 수 있습니다. 알림의 기본 사항 및 이를 통해 사용자 중심 알림을 전달하는 방법에 대한 자세한 내용은 Microsoft Graph 알림 개요를 참조하세요.

Graph 알림 등을 비롯한 프로젝트 로마 SDK의 모든 기능은 연결된 디바이스 플랫폼이라는 기본 플랫폼을 기반으로 구축됩니다. 이 가이드는 연결된 디바이스 플랫폼을 시작하는 데 필요한 단계를 안내하고 SDK에서 API를 사용하여 Graph 알림 관련 기능을 구현하는 방법을 설명하도록 설계되었습니다.

아래 단계에서는 GitHub에서 사용할 수 있는 프로젝트 로마 iOS 샘플 앱의 코드를 참조합니다.

알림 시나리오와 관련된 참조 문서에 대한 링크는 API 참조 페이지를 참조하세요.

연결된 디바이스 플랫폼 및 알림 설정

앱 등록

근거리 공유 API를 제외하고 프로젝트 로마 SDK의 거의 모든 기능에는 MSA(Microsoft Account) 또는 AAD(Azure Active Directory) 인증이 필요합니다. MSA가 아직 없는 경우 사용하려면 account.microsoft.com에 등록하세요.

참고

AAD(Azure Active Directory) 계정은 디바이스 릴레이 API에서 지원되지 않습니다.

선택한 인증 방법을 사용하여 애플리케이션 등록 포털의 지침에 따라 Microsoft에 앱을 등록해야 합니다. Microsoft 개발자 계정이 없는 경우 새로 만들어야 합니다.

MSA를 사용하여 앱을 등록하는 경우 클라이언트 ID 문자열을 받아야 합니다. 나중에 사용할 수 있도록 저장합니다. 이렇게 하면 앱이 Microsoft의 연결된 디바이스 플랫폼 리소스에 액세스할 수 있습니다. AAD를 사용하는 경우 Azure Active Directory 인증 라이브러리에서 클라이언트 ID 문자열을 가져오는 방법에 대한 지침을 참조하세요.

SDK 추가

연결된 디바이스 플랫폼을 iOS 앱에 추가하는 가장 간단한 방법은 CocoaPods 종속성 관리자를 사용하는 것입니다. iOS 프로젝트의 Podfile로 이동하고 다음 항목을 삽입합니다.

platform :ios, "10.0"
workspace 'iOSSample'

target 'iOSSample' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

	pod 'ProjectRomeSdk'

  # Pods for iOSSample

참고

CocoaPod를 사용하려면 프로젝트의 .xcworkspace 파일을 사용해야 합니다.

인증 및 계정 관리 설정

연결된 디바이스 플랫폼에는 등록 프로세스에서 사용할 유효한 OAuth 토큰이 필요합니다. OAuth 토큰을 생성하고 관리하는 데 원하는 방법을 사용할 수 있습니다. 그러나 개발자가 플랫폼 사용을 시작할 수 있도록 돕기 위해 앱에서 새로 고침 토큰을 생성하고 관리하는 데 사용할 수 있는 인증 공급 업체를 iOS 샘플 앱의 일부로 포함시켰습니다.

제공된 코드를 사용하지 않는 경우 MCDConnectedDevicesAccountManager 인터페이스를 직접 구현해야 합니다.

MSA를 사용하는 경우 다음과 같은 범위를 로그인 요청에 포함시킵니다. "wl.offline_access", "ccs.ReadWrite", "dds.read", "dds.register", "wns.connect", "asimovrome.telemetry""https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp".

참고

AAD(Azure Active Directory) 계정은 디바이스 릴레이 API에서 지원되지 않습니다.

AAD 계정을 사용하는 경우 다음 대상을 요청해야 합니다. "https://cdpcs.access.microsoft.com", "https://cs.dds.microsoft.com", "https://wns.windows.com/""https://activity.microsoft.com".

제공된 MCDConnectedDevicesAccountManager 구현을 사용하든 사용하지 않든, AAD를 사용하는 경우 Azure Portal(portal.azure.com > Azure Active Directory > 앱 등록)의 앱 등록에서 다음 사용 권한을 지정해야 합니다.

  • Microsoft 활동 피드 서비스
    • 이 앱에 대한 사용자 알림 전송 및 수정
    • 사용자의 활동 피드에 앱 활동 읽기 및 쓰기
  • Windows 알림 서비스
    • Windows 알림 서비스에 디바이스 연결
  • Microsoft 디바이스 디렉터리 서비스
    • 디바이스 목록 보기
    • 디바이스 및 앱 목록에 추가
  • Microsoft 명령 서비스
    • 사용자 디바이스와 통신
    • 사용자 디바이스 읽기

푸시 알림에 대해 앱 등록

Apple 푸시 알림 지원을 위해 애플리케이션을 Apple에 등록합니다. 보낸 사람 ID 및 받은 서버 키는 나중에 필요하기 때문 기록해 두어야 합니다.

등록이 되면 푸시 알림 기능을 앱의 연결된 디바이스 플랫폼과 연결해야 합니다.

self.notificationRegistration = [[MCDConnectedDevicesNotificationRegistration alloc] init];
    if ([[UIApplication sharedApplication] isRegisteredForRemoteNotifications])
    {
        self.notificationRegistration.type = MCDNotificationTypeAPN;
    }
    else
    {
        self.notificationRegistration.type = MCDNotificationTypePolling;
    }
    self.notificationRegistration.appId = [[NSBundle mainBundle] bundleIdentifier];
    self.notificationRegistration.appDisplayName = (NSString*)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
    self.notificationRegistration.token = deviceToken;
    self.isRegisteredWithToken = YES;

디바이스 간 환경을 위해 Microsoft Windows 개발자 센터에 앱 등록

경고

이 단계는 프로젝트 로마 기능을 사용하여 Windows 외 디바이스를 요청하거나 데이터에 액세스하려는 경우에만 필요합니다. Windows 디바이스만을 대상으로 하는 경우에는 이 단계를 완료할 필요가 없습니다.

앱을 Microsoft 개발자 대시보드의 디바이스 간 환경 기능에 등록해야 합니다. 이 절차는 위의 MSA 및 AAD 앱 등록과 다릅니다. 이 프로세스의 주요 목표는 플랫폼별 앱 ID를 연결된 디바이스 플랫폼에서 인식되는 플랫폼 간 앱 ID와 매핑하는 것입니다. 이 단계에서는 앱에 사용되는 모바일 플랫폼에 해당하는 네이티브 푸시 알림 서비스를 사용하여 알림을 전송할 수 있도록 설정할 수도 있습니다. iOS의 경우 APNS(Apple Push Notification Service)를 통해 iOS 앱 엔드포인트에 알림을 보낼 수 있습니다.

개발자 센터 대시보드로 이동하여 왼쪽 탐색 창의 디바이스 간 환경으로 이동하고 새 디바이스 간 앱 구성을 선택합니다. 개발자 센터 대시보드 – 디바이스 간 환경

개발자 센터 온보딩 프로세스에는 다음과 같은 단계가 필요합니다.

  • 지원되는 플랫폼 선택 - 앱이 존재하고 디바이스 간 환경에서 사용할 수 있는 플랫폼을 선택합니다. Graph 알림 통합의 경우, 사용 중인 플랫폼에 따라 Windows, Android 및/또는 iOS 중에서 선택할 수 있습니다. 디바이스 간 환경 – 지원되는 플랫폼

  • 앱 ID 제공 – 사용 중인 각 플랫폼에 대한 앱 ID를 제공합니다. iOS 앱의 경우, 프로젝트를 만들 때 앱에 할당한 패키지 이름입니다. 플랫폼당 다른 ID(최대 10개)를 추가할 수 있습니다. 동일한 앱 또는 다른 앱의 버전이 여러 개인 경우, 동일한 사용자를 대상으로 하는 앱 서버에서 보낸 동일한 알림을 수신할 수 있도록 하려는 경우입니다. 디바이스 간 환경 – 앱 ID

  • 위의 MSA/AAD 앱 등록 단계에서 얻은 MSA 및/또는 AAD 앱 등록에서 앱 ID를 선택하거나 제공합니다. 디바이스 간 환경 – MSA 및 AAD 앱 등록

  • 앱과 관련된 네이티브 알림 플랫폼에 대한 사용자 자격 증명을 제공하여(Windows용 WNS, Android용 FCM 및 iOS용 APNS) 사용자 대상 알림을 게시할 때 앱 서버에서 알림을 전송할 수 있도록 설정합니다. 디바이스 간 환경 – 푸시 자격 증명

  • 마지막으로 디바이스 간 앱 도메인을 확인하여 앱에 도메인 소유권이 있고 이것을 앱의 디바이스 간 ID로 사용할 수 있는지 확인합니다. 디바이스 간 환경 - 도메인 확인

플랫폼 사용

플랫폼의 인스턴스 만들기

시작하려면 플랫폼을 인스턴스화하면 됩니다.

MCDConnectedDevicesPlatform* platform = [MCDConnectedDevicesPlatform new];

MCDConnectedDevicesAccountManager 구독

플랫폼에 액세스하려면 인증된 사용자가 필요합니다. 올바른 계정을 사용하려면 MCDConnectedDevicesAccountManager 이벤트를 구독해야 합니다.

[MCDConnectedDevicesPlatform* platform.accountManager.accessTokenRequested
     subscribe:^(MCDConnectedDevicesAccountManager* _Nonnull manager __unused,
                 MCDConnectedDevicesAccessTokenRequestedEventArgs* _Nonnull request __unused) {

                    // Get access token

                 }
[MCDConnectedDevicesPlatform* platform.platform.accountManager.accessTokenInvalidated
     subscribe:^(MCDConnectedDevicesAccountManager* _Nonnull manager __unused,
                 MCDConnectedDevicesAccessTokenInvalidatedEventArgs* _Nonnull request) {

                      // Refresh and renew existing access token

                 }

MCDConnectedDevicesNotificationRegistrationManager 구독

마찬가지로 플랫폼은 알림을 사용하여 디바이스 간에 명령을 전송합니다. 따라서 클라우드 등록 상태가 사용 중인 계정에 대해 유효하도록 하려면 MCDConnectedDevicesNotificationRegistrationManager 이벤트를 구독해야 합니다. MCDConnectedDevicesNotificationRegistrationState를 사용하여 상태를 확인합니다.

[MCDConnectedDevicesPlatform* platform.notificationRegistrationManager.notificationRegistrationStateChanged
     subscribe:^(MCDConnectedDevicesNotificationRegistrationManager* manager __unused,
                 MCDConnectedDevicesNotificationRegistrationStateChangedEventArgs* args __unused) {

                     // Check state using MCDConnectedDevicesNotificationRegistrationState enum

                 }

플랫폼 시작

플랫폼이 초기화되고 이벤트 핸들러가 설치되었으므로 이제 원격 시스템 디바이스 검색을 시작할 준비가 되었습니다.

[MCDConnectedDevicesPlatform* platform start];

앱에 알려진 사용자 계정 검색

앱에 알려진 사용자 계정 목록이 MCDConnectedDevicesAccountManager와 올바르게 동기화되는지 확인하는 것이 중요합니다.

MCDConnectedDevicesAccountManager.addAccountAsync를 사용하여 새 사용자 계정을 추가합니다.

[MCDConnectedDevicesPlatform* platform.accountManager
     addAccountAsync:self.mcdAccount
     callback:^(MCDConnectedDevicesAddAccountResult* _Nonnull result, NSError* _Nullable error) {

     // Check state using **MCDConnectedDevicesAccountAddedStatus** enum

     }

잘못된 계정을 제거하기 위해 MCDConnectedDevicesAccountManager.removeAccountAsync를 사용할 수 있습니다.

 [MCDConnectedDevicesPlatform* platform.accountManager
     removeAccountAsync:existingAccount
     callback:^(MCDConnectedDevicesRemoveAccountResult* _Nonnull result __unused, NSError* _Nullable error) {

                    // Remove invalid user account

     }

Graph 알림 채널 초기화

프로젝트 로마 SDK를 사용하면 Graph 알림, 사용자 활동 등을 비롯한 다양한 형식의 사용자 데이터를 수신하고 관리하기 위해 앱에서 다양한 채널을 구독할 수 있습니다. 이러한 데이터는 모두 MCDUserDataFeed에 저장되고 동기화됩니다. MCDUserNotification은 Graph 알림을 통해 보낸 사용자 대상 알림에 해당하는 클래스 및 데이터 형식입니다. Graph 알림과 통합하고 앱 서버에서 게시한 MCDUserNotification을 받기 시작하려면 먼저 MCDUserNotificationChannel을 만들어서 사용자 데이터 피드를 초기화해야 합니다. 이 작업은 위의 플랫폼 초기화 단계와 동일한 방법으로 처리해야 합니다. 앱이 포그라운드로 올 때마다(플랫폼 초기화 이전이 아님) 다시 확인하고 가능한 경우 다시 수행해야 합니다.

다음 메서드는 MCDUserNotificationChannel을 초기화합니다.

// You must be logged in to use UserNotifications
NSArray<MCDUserAccount*>* accounts = [[AppDataSource sharedInstance].accountProvider getUserAccounts];
if (accounts.count > 0)
{
    // Get a UserNotification channel, getting the default channel
    NSLog(@"Creating UserNotificationChannel");
    NSArray<MCDUserAccount*>* accounts = [[AppDataSource sharedInstance].accountProvider getUserAccounts];
    MCDUserDataFeed* userDataFeed = [MCDUserDataFeed userDataFeedForAccount:accounts[0]
        platform:[AppDataSource sharedInstance].platform
        activitySourceHost:CROSS_PLATFORM_APP_ID];
    NSArray<MCDSyncScope*>* syncScopes = @[ [MCDUserNotificationChannel syncScope] ];
    [userDataFeed addSyncScopes:syncScopes];
    self.channel = [MCDUserNotificationChannel userNotificationChannelWithUserDataFeed:userDataFeed];
}
else
{
    NSLog(@"Must log in to receive notifications for the logged in user!");
    self.createNotificationStatusField.text = @"Need to be logged in!";
}

이 때, channelMCDUserNotificationChannel 참조가 있어야 합니다.

들어오는 MCDUserNotification을 수신하고 MCDUserNotification 기록에 액세스하도록 MCDUserNotificationReader 만들기

앞에서 본 것처럼, 앱 클라이언트에 도착하는 초기 APNS 무음 메시지에는 숄더 탭만 포함되어 있으며, 이 숄더 탭 페이로드를 연결된 디바이스 플랫폼에 전달해야만 SDK를 트리거하여 연결된 디바이스 서버와 전체 동기화를 수행할 수 있습니다. 여기에는 앱 서버에서 게시한 모든 MCDUserNotifications이 포함되어 있습니다. 그러면 숄더 탭에 해당하는 앱 서버에서 게시한 전체 알림 페이로드를 가져오게 됩니다. (그리고 이전에 알림이 게시되었지만 디바이스 연결 또는 기타 문제로 인해 앱 클라이언트에 수신되지 않은 경우, 이러한 알림도 함께 가져오게 됩니다.) 이러한 실시간 동기화가 SDK에서 지속적으로 수행되기 때문에 로그인된 사용자의 MCDUserNotification 데이터 피드의 로컬 캐시에 앱 클라이언트가 액세스할 수 있습니다. 이 경우 MCDUserNotificationReader를 사용하면 앱 클라이언트에서 이 데이터 피드에 액세스할 수 있습니다. 그러면 이벤트 수신기를 통해 최신 알림 페이로드를 받거나 사용자의 알림 기록 보기 모델로 사용할 수 있는 전체 MCDUserNotification 컬렉션에 액세스할 수 있습니다.

MCDUserNotification 받기

우선 MCDUserNotificationReader를 인스턴스화하고 reader에 이미 있는 기존의 모든 MCDUserNotification(사용하도록 설정하려는 환경에서 해당 정보를 사용하도록 하려면)을 가져와야 합니다. 특정 디바이스 엔드포인트가 사용자가 앱을 설치한 유일한 엔드포인트나 첫 번째 엔드포인트가 아닐 수도 있으니 앱 서버가 로그인된 사용자에게 알림을 이미 게시했다고 항상 가정하는 것이 안전합니다. 그런 다음, 연결된 디바이스 플랫폼에서 동기화가 완료되고 알려줄 만한 새로운 변경 내용이 있을 때 트리거되는 이벤트 수신기를 추가합니다. Graph 알림의 경우, 새로운 변경 내용은 앱 서버에서 게시한 새로 받은 MCDUserNotification이거나 서버 또는 동일한 사용자가 로그인한 다른 등록된 엔드포인트에서 발생한 MCDUserNotifcation 업데이트, 삭제 및 만료일 수 있습니다.

이 이벤트 수신기는 기본 비즈니스 논리를 처리하고 시나리오에 따라 알림 페이로드의 콘텐츠를 "소비"하는 곳입니다. 현재 APNS 무음 알림을 사용하여 OS 수준 알림 센터에서 시각적 알림을 구성하거나 무음 알림의 콘텐츠를 사용하여 일부 앱 내 UI를 업데이트하는 경우 해당 작업을 수행할 수 있는 곳입니다.

// Instantiate the reader from a MCDUserNotificationChannel
// Add a data change listener to subscribe to new changes when new notifications or notification updates are received
- (void)setupWithAccount:(MCDUserAccount*)account {
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
        @synchronized (self) {
            MCDUserDataFeed* dataFeed = [MCDUserDataFeed userDataFeedForAccount:account platform:_platform activitySourceHost:@"graphnotifications.sample.windows.com"];
            [dataFeed addSyncScopes:@[[MCDUserNotificationChannel syncScope]]];
            self.channel = [MCDUserNotificationChannel userNotificationChannelWithUserDataFeed:dataFeed];
            self.reader = [self.channel createReader];
            
            __weak typeof(self) weakSelf = self;
            _readerRegistrationToken = [self.reader addDataChangedListener:^(__unused MCDUserNotificationReader* source) {
                NSLog(@"ME123 Got a change!");
                if (weakSelf) {
                    [weakSelf forceRead];
                } else {
                    NSLog(@"ME123 WEAKSELF FOR CHANGES IS NULL!!!");
                }
            }];
            
            [self forceRead];
        }
    });
}

// this is your own business logic when the event listener is fired
// In this case, the app reads the existing batch of notifications in the store and handle any new incoming notifications or notification updates after that
- (void)forceRead {
    NSLog(@"ME123 Forced to read!");
    [self.reader readBatchAsyncWithMaxSize:NSUIntegerMax completion:^(NSArray<MCDUserNotification *> * _Nullable notifications, NSError * _Nullable error) {
        if (error) {
            NSLog(@"ME123 Failed to read batch with error %@", error);
        } else {
            [self _handleNotifications:notifications];
            NSLog(@"ME123 Have %ld listeners", self.listenerMap.count);
            for (void (^listener)(void) in self.listenerMap.allValues) {
                NSLog(@"ME123 Calling a listener about an update!");
                listener();
            }
        }
    }];
}

기존 MCDUserNotification 상태 업데이트

이전 섹션에서는 reader를 통해 받은 MCDUserNotification 변경 내용이 기존 MCDUserNotification에 대한 상태 업데이트, 즉 해제되었거나 읽힌 것으로 표시되는지 여부일 수도 있다고 설명했습니다. 이 경우 앱 클라이언트는 특정 디바이스에서 해당하는 시각적 알림을 제거하여 유니버설 해제가 가능하도록 설정하는 등의 작업 중에서 수행할 작업을 선택할 수 있습니다. 다시 한번 생각해 보면, 앱 클라이언트가 다른 디바이스에서 이 MCDUserNotification 변경 업데이트를 시작한 클라이언트인 경우가 많습니다. MCDUserNotification의 상태를 업데이트하는 시간을 선택할 수 있지만, 일반적으로 사용자가 해당 디바이스에서 해당 시각적 알림을 처리할 때 업데이트되거나 사용자가 사용하도록 설정한 일부 앱 내 환경에서 사용자가 알림을 추가로 처리합니다. 흐름의 예는 다음과 같습니다. 앱 서버에서 사용자 A를 대상으로 하는 알림을 게시합니다. 사용자 A는 앱 클라이언트를 설치한 PC와 휴대폰 모두에서 이 알림을 받습니다. 사용자는 PC에서 알림을 클릭하고, 해당 작업을 처리하는 앱을 추적합니다. 그런 다음, 이 PC의 앱 클라이언트에서 연결된 디바이스 플랫폼 SDK를 호출하여 이 업데이트가 해당 사용자의 모든 디바이스에서 동기화되도록 해당 사용자 알림의 상태를 업데이트합니다. 다른 앱 클라이언트는 이 상태 업데이트를 실시간으로 받는 즉시 디바이스의 알림 센터/알림 트레이/알림 센터에서 해당 시각적 경고/메시지/알림 메시지를 제거합니다. 이는 사용자의 디바이스에서 알림이 일반적으로 해제되는 방식입니다.

MCDUserNotification 클래스는 현재 두 가지 유형의 상태 업데이트를 제공합니다. 즉 MCDUserNotificationReadState 또는 MCDUserNotificationUserActionState를 수정하고, 알림이 업데이트되면 수행되어야 하는 작업에 대해 사용자 고유의 논리를 정의할 수 있습니다. 예를 들어 동작 상태를 Activated(활성화됨) 또는 Dismissed(해제됨)로 표시하고, 해당 값을 중심으로 결정하여 유니버설 해제를 구현할 수 있습니다. 또는 읽기 상태를 Read(읽음) 또는 Unread(읽지 않음)로 표시하고, 이에 따라 앱 내 알림 기록 보기에 표시할 알림을 결정할 수 있습니다.

- (void)dismissNotification:(MCDUserNotification*)notification {
    @synchronized (self) {
        notification.userActionState = MCDUserNotificationUserActionStateDismissed;
        [notification saveAsync:^(__unused MCDUserNotificationUpdateResult * _Nullable result, __unused NSError * _Nullable err) {
            NSLog(@"ME123 Dismiss notification with result %d error %@", result.succeeded, err);
        }];
    }
}