> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 크로스 플랫폼 Live Activity SDK 설정

> Push To Start 및 기본 Live Activity 유형을 지원하는 React Native, Flutter, Unity, Cordova 등과 같은 OneSignal의 래퍼 SDK에서 Live Activities를 구현하는 방법을 알아보세요.

Live Activities는 비교적 새로운 iOS 기능이며 네이티브 구현이 필요하므로 React Native, Flutter, Unity, Cordova 등과 같은 크로스 플랫폼 프레임워크를 사용할 때 어려움을 겪을 수 있습니다. 프로세스를 단순화하기 위해 OneSignal의 SDK에는 네이티브 코드 요구 사항을 최소화하는 기능이 포함되어 있어 지원되는 플랫폼 전체에서 간소화된 Live Activity 통합이 가능합니다.

## 요구 사항

* 최신 버전의 SDK.
* iOS 16.1+ 및 iPadOS 17+
* [.p8 APNs 키](./ios-p8-token-based-connection-to-apns)를 사용하세요. Apple은 Live Activities에서 p12 인증서를 지원하지 않습니다.
* Xcode 14 이상

## 설정

### 1. SDK 설정

앱에 최신 버전의 Mobile SDK를 설정했는지 확인하세요. Live Activities는 웹사이트 또는 Web SDK에서 사용할 수 없습니다.

<Columns cols={2}>
  <Card href="./unity-sdk-setup">
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: '1rem' }}>
      <div style={{ flexShrink: 0, width: '40px', height: '40px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/cms/Docs/docs-unity.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=4f65e7750194bcbdc08b8f1549d27eb5" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} width="96" height="96" data-path="images/docs/cms/Docs/docs-unity.png" />
      </div>

      <div>
        <div style={{ fontWeight: '600', fontSize: '1.1rem', marginBottom: '0.25rem' }}>
          Unity
        </div>

        <div>
          Unity 기반 모바일 앱용 크로스 플랫폼 SDK 가이드.
        </div>
      </div>
    </div>
  </Card>

  <Card href="./react-native-sdk-setup">
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: '1rem' }}>
      <div style={{ flexShrink: 0, width: '40px', height: '40px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/cms/Docs/docs-react.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=dddbb392fdea1f20e0d9e20e6d90098a" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} width="96" height="96" data-path="images/docs/cms/Docs/docs-react.png" />
      </div>

      <div>
        <div style={{ fontWeight: '600', fontSize: '1.1rem', marginBottom: '0.25rem' }}>
          React Native & Expo
        </div>

        <div>
          React Native 및 Expo 환경 설정 지침.
        </div>
      </div>
    </div>
  </Card>

  <Card href="./flutter-sdk-setup">
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: '1rem' }}>
      <div style={{ flexShrink: 0, width: '40px', height: '40px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/cms/Docs/docs-flutter.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=09904d15d1b7bd1c5f902a6101c13a22" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} width="96" height="96" data-path="images/docs/cms/Docs/docs-flutter.png" />
      </div>

      <div>
        <div style={{ fontWeight: '600', fontSize: '1.1rem', marginBottom: '0.25rem' }}>
          Flutter
        </div>

        <div>
          Dart를 사용하는 Flutter 앱용 SDK 가이드.
        </div>
      </div>
    </div>
  </Card>

  <Card href="./cordova-sdk-setup">
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: '1rem' }}>
      <div style={{ flexShrink: 0, width: '40px', height: '40px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/cms/Docs/docs-ionic.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=b9e33554d01ff7413f11f9bbf1f4a1b2" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} width="96" height="96" data-path="images/docs/cms/Docs/docs-ionic.png" />
      </div>

      <div>
        <div style={{ fontWeight: '600', fontSize: '1.1rem', marginBottom: '0.25rem' }}>
          Ionic & Ionic Capacitor
        </div>

        <div>
          Ionic 및 Capacitor 하이브리드 모바일 앱 설정.
        </div>
      </div>
    </div>
  </Card>

  <Card href="./net-sdk-setup">
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: '1rem' }}>
      <div style={{ flexShrink: 0, width: '40px', height: '40px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <img src="https://mintcdn.com/onesignal/F6GiolM7XhfdYah_/images/docs/cms/Docs/docs-logo-dotnet.svg?fit=max&auto=format&n=F6GiolM7XhfdYah_&q=85&s=89024e079243d091d9bd6fda0493242d" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} width="48" height="48" data-path="images/docs/cms/Docs/docs-logo-dotnet.svg" />
      </div>

      <div>
        <div style={{ fontWeight: '600', fontSize: '1.1rem', marginBottom: '0.25rem' }}>
          .NET MAUI
        </div>

        <div>
          .NET MAUI 앱과 통합하기 위한 가이드.
        </div>
      </div>
    </div>
  </Card>

  <Card href="./huawei-sdk-setup">
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: '1rem' }}>
      <div style={{ flexShrink: 0, width: '40px', height: '40px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/cms/Docs/docs-huawei.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=d15371678eda8514d135b2d4cc51a56a" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} width="96" height="96" data-path="images/docs/cms/Docs/docs-huawei.png" />
      </div>

      <div>
        <div style={{ fontWeight: '600', fontSize: '1.1rem', marginBottom: '0.25rem' }}>
          Huawei Android Native
        </div>

        <div>
          HMS 푸시 서비스를 사용하는 Huawei 기기용 SDK 설정.
        </div>
      </div>
    </div>
  </Card>
</Columns>

### 2. 새로운 `setupDefault` 메서드 추가

OneSignal SDK에 `DefaultLiveActivityAttributes` 유형에 대한 LiveActivity 수명 주기를 관리하도록 지시하려면 `setupDefault` 메서드를 호출할 수 있습니다. 이 메서드를 사용하면 [Start Live Activity](/reference/start-live-activity) 및 [Update Live Activity](/reference/update-live-activity-api) API를 모두 사용하여 기본 Live Activity를 시작/업데이트/종료할 수 있습니다.

<CodeGroup>
  ```javascript React Native/Expo theme={null}
  import { OneSignal } from 'react-native-onesignal'

  //Push To Start
  OneSignal.LiveActivities.setupDefault()

  //Launching the Live Activity from within the app (not needed for push to start)
  const activityId = "my_activity_id"
  const attributes = { title: "Sample Title" } ;
  const content = { message: { en: "message" } };
  OneSignal.LiveActivities.startDefault(activityId, attributes, content);

  ```

  ```csharp Unity theme={null}
  using OneSignalSDK;

  //Push To Start
  OneSignal.LiveActivities.SetupDefault();

  //Launching the Live Activity from within the app (not needed for push to start)
  string activityId = "my_activity_id";

  OneSignal.LiveActivities.StartDefault(
    activityId,
    new Dictionary<string, object>() {
        { "title", "Welcome!" }
    },
    new Dictionary<string, object>() {
        { "message", new Dictionary<string, object>() {
            { "en", "Hello World!"}
        }},
    });
  ```

  ```javascript Cordova/Ionic theme={null}
  /*Cordova*/

  //Push To Start
  window.plugins.OneSignal.LiveActivities.setupDefault();

  //Launching the Live Activity from within the app (not needed for push to start)
  const activityId = "my_activity_id";
  const attributes = { title: "Sample Title" };
  const content = { message: { en: "message" } };
  window.plugins.OneSignal.LiveActivities.startDefault(
    activityId,
    attributes,
    content
  );

  /*Ionic/Capacitor*/
  import OneSignal from "onesignal-cordova-plugin";

  //Push To Start
  OneSignal.LiveActivities.setupDefault();

  //Launching the Live Activity from within the app (not needed for push to start)
  const activityId = "my_activity_id";
  const attributes = { title: "Sample Title" };
  const content = { message: { en: "message" } };
  OneSignal.LiveActivities.startDefault(activityId, attributes, content);
  ```

  ```csharp .NET theme={null}
  using OneSignalSDK;

  //Push To Start
  OneSignal.LiveActivities.SetupDefault();

  //Launching the Live Activity from within the app (not needed for push to start)
  string activityId = "my_activity_id";

  OneSignal.LiveActivities.StartDefault(
    activityId,
    new Dictionary<string, object>() {
        { "title", "Welcome!" }
    },
    new Dictionary<string, object>() {
        { "message", new Dictionary<string, object>() {
            { "en", "Hello World!"}
        }},
    });
  ```

  ```javascript Flutter theme={null}
  import 'package:onesignal_flutter/onesignal_flutter.dart';

  OneSignal.LiveActivities.setupDefault()

  //Launching the Live Activity from within the app (not needed for push to start)
  const String activityId = "my_activity_id";
  OneSignal.LiveActivities.startDefault(activityId!, {
    "title": "Welcome!"
    }, {
    "message": {"en": "Hello World!"},
  });
  ```
</CodeGroup>

### 3. Activity Widget 만들기

<Steps>
  <Step title="Info.plist 업데이트">
    Xcode에서 메인 타겟의 `Info.plist`를 열고 `Supports Live Activities` 키를 **Boolean**으로 추가하고 `YES`로 설정하세요.

    <Frame caption="Info에 Supports Live Activities 키를 추가하고 값을 Boolean YES로 설정">
      <img src="https://mintcdn.com/onesignal/yt4lRKoquAlWvRvF/images/live-activities/info-la-setting.png?fit=max&auto=format&n=yt4lRKoquAlWvRvF&q=85&s=e839231401651b71d0ae8d48614ec130" width="2166" height="1488" data-path="images/live-activities/info-la-setting.png" />
    </Frame>

    <Note>
      Live Activities를 업데이트할 때 Apple이 업데이트의 긴급성을 결정하는 데 사용하는 "priority"를 설정할 수 있는 옵션이 있습니다. Apple에는 높은 우선순위 플래그를 너무 자주 사용하는 요청을 제한하는 내부 임계값이 있습니다.

      Live Activities에 대한 사용 사례가 더 빈번한 높은 우선순위 업데이트에 의존하는 경우 [Apple의 개발자 문서](https://developer.apple.com/documentation/activitykit/starting-and-updating-live-activities-with-activitykit-push-notifications#Determine-the-update-frequency)에 지시된 대로 Info.plist에 `NSSupportsLiveActivitiesFrequentUpdates` 키를 Boolean 유형으로 YES로 설정하여 추가할 수 있습니다. Live Activity가 푸시 예산을 초과하면 사용자에게 대화 상자가 표시되며 Live Activity를 계속 허용하면 원활한 사용자 경험을 위해 예산이 자동으로 증가합니다.
    </Note>
  </Step>

  <Step title="Widget Extension 만들기">
    Xcode에서 **File > New > Target... > Widget Extension**으로 이동하세요.

    <Frame caption="Xcode에서 앱용 새 Widget Extension 타겟 추가.">
      <img src="https://mintcdn.com/onesignal/FXJz6yFfOqztaEND/images/live-activities/live-activity-widget-extension.png?fit=max&auto=format&n=FXJz6yFfOqztaEND&q=85&s=60a52d6484203c4d6af21bc3a7da5e62" width="2166" height="1488" data-path="images/live-activities/live-activity-widget-extension.png" />
    </Frame>

    선택하고 **Next**를 누르세요.

    이름을 제공하여(예: `OneSignalWidget`) Widget Extension을 구성하고 **Include Live Activity**가 선택되어 있는지 확인하세요. 그런 다음 **Finish**를 클릭하세요.

    <Frame caption="Live Activity용 Widget Extension 옵션.">
      <img src="https://mintcdn.com/onesignal/yt4lRKoquAlWvRvF/images/live-activities/OneSignalWidget.png?fit=max&auto=format&n=yt4lRKoquAlWvRvF&q=85&s=47412314963f6fbd58fd2c7d3a529322" width="2166" height="1488" data-path="images/live-activities/OneSignalWidget.png" />
    </Frame>

    스키마를 활성화하라는 메시지가 표시되면 **Don't Activate**를 클릭하세요.

    <Frame caption="Live Activity용 Widget Extension 옵션.">
      <img src="https://mintcdn.com/onesignal/yt4lRKoquAlWvRvF/images/live-activities/la-scheme-activation.png?fit=max&auto=format&n=yt4lRKoquAlWvRvF&q=85&s=d3a2207ff2b5988c63c2abd631a72541" width="2166" height="1488" data-path="images/live-activities/la-scheme-activation.png" />
    </Frame>
  </Step>

  <Step title="Podfile에 OneSignalXCFramework 추가">
    프로젝트의 Targets 목록에서 widget extension 타겟의 이름을 찾으세요. 예제의 이름은 `OneSignalWidgetExtension`입니다.

    <Frame caption="widget extension 타겟의 이름 찾기">
      <img src="https://mintcdn.com/onesignal/yt4lRKoquAlWvRvF/images/live-activities/cocoapods-la-extension-name.png?fit=max&auto=format&n=yt4lRKoquAlWvRvF&q=85&s=850a91387539587802306a66771435eb" width="2166" height="1488" data-path="images/live-activities/cocoapods-la-extension-name.png" />
    </Frame>

    `Podfile`을 열고 다음 코드를 추가하세요. `OneSignalWidgetExtension`을 widget extension 타겟의 이름으로 교체하세요.

    ```ruby Podfile theme={null}
    target 'OneSignalWidgetExtension' do
      #use_frameworks!
      pod 'OneSignalXCFramework', '>= 5.0.0', '< 6.0'
    end
    ```

    Xcode를 닫고 `pod repo update && pod install`을 실행하여 `OneSignalLiveActivities` pod를 설치하세요.
  </Step>
</Steps>

### 4. LiveActivity.swift 파일 설정

Xcode에서 *WidgetExtensionLiveActivity.swift* 파일을 여세요.

화면 오른쪽의 Inspector 패널을 여세요. **Target Membership** 내에서 **+** 버튼을 클릭하고 Runner 타겟을 선택하세요.

<Frame caption="메인 타겟 멤버십 허용">
  <img src="https://mintcdn.com/onesignal/FXJz6yFfOqztaEND/images/live-activities/target-membership.png?fit=max&auto=format&n=FXJz6yFfOqztaEND&q=85&s=3315253623dfec6c13a56ff30a156772" width="2392" height="1488" data-path="images/live-activities/target-membership.png" />
</Frame>

\_WidgetExtensionLiveActivity.swift\_의 내용을 다음 기본 Live Activity 레이아웃으로 업데이트하세요. 이 Widget의 값은 위젯에 표시하려는 모든 것으로 변경할 수 있으며 setupDefault 메서드가 이러한 속성에 대한 구조체 정의를 처리합니다.

```swift Swift theme={null}
import ActivityKit
import WidgetKit
import SwiftUI
import OneSignalLiveActivities

// Your struct name might be different here
@available(iOS 16.2, *)
struct OneSignalWidgetLiveActivity: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: DefaultLiveActivityAttributes.self) { context in
            // Lock screen / banner UI
            VStack {
                Spacer()

                Text("Title: " + (context.attributes.data["title"]?.asString() ?? ""))
                    .font(.headline)

                Spacer()

                HStack {
                    Spacer()
                    Text(context.state.data["message"]?.asDict()?["en"]?.asString() ?? "Default Message")
                    Spacer()
                }

                Text("INT: " + String(context.state.data["intValue"]?.asInt() ?? 0))
                Text("DBL: " + String(context.state.data["doubleValue"]?.asDouble() ?? 0.0))
                Text("BOL: " + String(context.state.data["boolValue"]?.asBool() ?? false))

                Spacer()
            }
            .activitySystemActionForegroundColor(.black)
            .activityBackgroundTint(.white)

        } dynamicIsland: { _ in
            DynamicIsland {
                // Expanded UI
                DynamicIslandExpandedRegion(.leading) {
                    Text("Leading")
                }
                DynamicIslandExpandedRegion(.trailing) {
                    Text("Trailing")
                }
                DynamicIslandExpandedRegion(.bottom) {
                    Text("Bottom")
                    // More content
                }
            } compactLeading: {
                Text("L")
            } compactTrailing: {
                Text("T")
            } minimal: {
                Text("Min")
            }
            .widgetURL(URL(string: "http://www.apple.com"))
            .keylineTint(Color.red)
        }
    }
}

```

***

## Live Activity 테스트

1. 앱을 시작하세요

2. [Start Live Activity API 레퍼런스](/reference/start-live-activity)에서 가능한 모든 필드를 확인하세요. 이러한 필드의 구조는 UI를 설정한 방법에 따라 다를 수 있습니다. 예를 들어:

* `"event_updates"`: Live Activity가 시작된 후 업데이트할 수 있는 동적 데이터입니다(코드 예제의 `context.state` 이후의 모든 것). context.state.data가 있으므로 이 필드에 데이터 객체와 코드 예제에 추가한 message 딕셔너리와 같은 추가 필드를 추가합니다. 사용 방법은 아래 예제 요청을 참조하세요.
* `"event_attributes"`: push to start 요청에서 설정되는 정적 데이터이며 Live Activity가 제거되거나 덮어쓰기될 때까지 동일한 값을 유지합니다.

3. push to start를 사용할 때 코드가 아닌 요청에서 `"activity_id"`를 설정합니다. 다른 Activity ID를 사용하면 새 Live Activities가 시작됩니다. 동일한 Activity ID를 사용하면 현재 해당 ID를 사용하는 위젯을 덮어씁니다.

4. url 경로에서 [OneSignal 앱 ID](./keys-and-ids)를, Authorization 헤더에서 [Rest API Key](./keys-and-ids#rest-api-key)를 변경했는지 확인하세요. 기본 설정을 사용하는 경우 `DefaultActivityAttributes` 유형은 변경할 수 없습니다. 또한 경로에 추가된 activity 유형은 대소문자를 구분하며 아래 예제에서 사용된 기본 activity 또는 정의한 것과 일치해야 합니다.

```curl curl theme={null}
curl --request POST \
     --url https://api.onesignal.com/apps/YOUR_APP_ID/activities/activity/DefaultLiveActivityAttributes \
     --header 'Authorization: key YOUR_REST_API_KEY' \
     --header 'Content-Type: application/json' \
     --header 'accept: application/json' \
     --data '
{
  "event": "start",
  "event_updates": {
    "data": {
      "message": {
        "en": "The message is nested in context.state.data[\"message\"] as a dictionary"
      },
      "intValue": 10,
      "doubleValue": 3.14,
      "boolValue": true
    }
  },
  "event_attributes": {
    "data": {
      "title": "this is set when the LA starts and does not get updated after"
    }
  },
  "activity_id": "my-activity-id",
  "name": "OneSignal Notification Name",
  "contents": {
    "en": "English Message"
  },
  "headings": {
    "en": "English Message"
  },
  "sound": "beep.wav",
  "priority": 10
}'
```

***

## 하위 수준 메서드

SDK의 최신 릴리스에도 추가된 자체 Push To Start 토큰을 생성하려는 경우 사용할 수 있는 선택적 메서드입니다. 이러한 메서드를 사용하려면 Xcode와 더 많이 상호 작용하고 Swift로 Push To Start용 자체 토큰을 생성해야 합니다. 이에 대한 가이드는 [여기](https://github.com/OneSignal/OneSignal-iOS-SDK/pull/1377#:~:text=Alternative%20\(low%20level\)%20method%20to%20setup%20Live%20Activities%20with%20OneSignal)에서 찾을 수 있습니다.

<CodeGroup>
  ```javascript React Native/Expo theme={null}
  //Setting the Push To Start Token
  OneSignal.LiveActivities.setPushToStartToken(activityType: string, token: string)

  //Removing the Push To Start Token
  OneSignal.LiveActivities.removePushToStartToken(activityType: string)

  ```

  ```csharp Unity theme={null}
  //Setting the Push To Start Token
  OneSignal.LiveActivities.SetPushToStartToken(string activityType, string token)

  //Removing the Push To Start Token
  OneSignal.LiveActivities.RemovePushToStartToken(string activityType)
  ```

  ```javascript Cordova/Ionic theme={null}
  /* Cordova */
  //Setting the Push To Start Token
  window.plugins.OneSignal.LiveActivities.setPushToStartToken(activityType: string, token: string)

  //Removing the Push To Start Token
  window.plugins.OneSignal.LiveActivities.removePushToStartToken(activityType: string)

  /* Ionic */
  //Setting the Push To Start Token
  OneSignal.LiveActivities.setPushToStartToken(activityType: string, token: string)

  //Removing the Push To Start Token
  OneSignal.LiveActivities.removePushToStartToken(activityType: string)
  ```

  ```csharp .NET theme={null}
  //Setting the Push To Start Token
  OneSignal.LiveActivities.SetPushToStartToken(string activityType, string token)

  //Removing the Push To Start Token
  OneSignal.LiveActivities.RemovePushToStartToken(string activityType)
  ```

  ```javascript Flutter theme={null}
  //Setting the Push To Start Token
  OneSignal.LiveActivities.setPushToStartToken(String activityType, String token)

  //Removing the Push To Start Token
  OneSignal.LiveActivities.removePushToStartToken(String activityType)
  ```
</CodeGroup>

***
