푸시 알림의 딥링크
Braze SDK에 무음 푸시 알림을 설정하는 방법을 알아보세요.
Prerequisites
이 기능을 사용하려면 먼저 Android Braze SDK를 통합해야 합니다.
범용 대리인 만들기
Android SDK는 콘텐츠 카드, 인앱 메시지, 푸시 알림에서 Braze가 여는 모든 딥링크를 사용자 지정 처리하도록 단일 위임 오브젝트를 설정할 수 있는 기능을 제공합니다.
위임 오브젝트는 IBrazeDeeplinkHandler
인터페이스를 구현하고 BrazeDeeplinkHandler.setBrazeDeeplinkHandler()
를 사용하여 설정해야 합니다. 대부분의 경우 위임은 앱의 Application.onCreate()
에서 설정해야 합니다.
다음은 YouTube URL의 커스텀 동작 및 커스텀 의도 플래그로 기본 UriAction
동작을 재정의하는 예제입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class CustomDeeplinkHandler implements IBrazeDeeplinkHandler {
private static final String TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler.class);
@Override
public void gotoNewsFeed(Context context, NewsfeedAction newsfeedAction) {
newsfeedAction.execute(context);
}
@Override
public void gotoUri(Context context, UriAction uriAction) {
String uri = uriAction.getUri().toString();
// Open YouTube URLs in the YouTube app and not our app
if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) {
uriAction.setUseWebView(false);
}
CustomUriAction customUriAction = new CustomUriAction(uriAction);
customUriAction.execute(context);
}
public static class CustomUriAction extends UriAction {
public CustomUriAction(@NonNull UriAction uriAction) {
super(uriAction);
}
@Override
protected void openUriWithActionView(Context context, Uri uri, Bundle extras) {
Intent intent = getActionViewIntent(context, uri, extras);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
if (intent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(intent);
} else {
BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link " + uri + ".");
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class CustomDeeplinkHandler : IBrazeDeeplinkHandler {
override fun gotoNewsFeed(context: Context, newsfeedAction: NewsfeedAction) {
newsfeedAction.execute(context)
}
override fun gotoUri(context: Context, uriAction: UriAction) {
val uri = uriAction.uri.toString()
// Open YouTube URLs in the YouTube app and not our app
if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) {
uriAction.useWebView = false
}
val customUriAction = CustomUriAction(uriAction)
customUriAction.execute(context)
}
class CustomUriAction(uriAction: UriAction) : UriAction(uriAction) {
override fun openUriWithActionView(context: Context, uri: Uri, extras: Bundle) {
val intent = getActionViewIntent(context, uri, extras)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
if (intent.resolveActivity(context.packageManager) != null) {
context.startActivity(intent)
} else {
BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link $uri.")
}
}
}
companion object {
private val TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler::class.java)
}
}
앱 설정에 대한 딥링킹
딥링크에서 앱 설정을 바로 열 수 있도록 하려면 커스텀 BrazeDeeplinkHandler
가 필요합니다. 다음 예제에서는 open_notification_page
라는 커스텀 키-값 페어를 통해 딥링크에서 앱 설정 페이지를 엽니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
BrazeDeeplinkHandler.setBrazeDeeplinkHandler(new IBrazeDeeplinkHandler() {
@Override
public void gotoUri(Context context, UriAction uriAction) {
final Bundle extras = uriAction.getExtras();
if (extras.containsKey("open_notification_page")) {
Intent intent = new Intent();
intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//for Android 5-7
intent.putExtra("app_package", context.getPackageName());
intent.putExtra("app_uid", context.getApplicationInfo().uid);
// for Android 8 and later
intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName());
context.startActivity(intent);
}
}
@Override
public void gotoNewsFeed(Context context, NewsfeedAction newsfeedAction) {}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
BrazeDeeplinkHandler.setBrazeDeeplinkHandler(object : IBrazeDeeplinkHandler {
override fun gotoUri(context: Context, uriAction: UriAction) {
val extras = uriAction.extras
if (extras.containsKey("open_notification_page")) {
val intent = Intent()
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
//for Android 5-7
intent.putExtra("app_package", context.packageName)
intent.putExtra("app_uid", context.applicationInfo.uid)
// for Android 8 and later
intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName)
context.startActivity(intent)
}
}
override fun gotoNewsFeed(context: Context, newsfeedAction: NewsfeedAction) {}
})
뉴스피드에 대한 딥링킹
News Feed is being deprecated. We recommend migrating to our Content Cards messaging channel instead—it’s more flexible, customizable, and reliable. To get started, check out Migrating from News Feed.
푸시 알림에서 Braze 뉴스피드에 딥링크를 연결하려면 뉴스피드 활동에 대한 사용자 지정 딥링크를 생성하세요.
그런 다음, 대시보드 또는 API를 통해 푸시 알림 캠페인을 설정할 때 알림이 뉴스피드 딥링크로 이동하도록 구성합니다.
WebView 활동 사용자 지정
기본적으로, 웹사이트 딥링크가 Braze에 의해 앱 내부에서 열리면 BrazeWebViewActivity
에 의해 처리됩니다. 이를 변경하려면:
com.braze.Constants.BRAZE_WEBVIEW_URL_EXTRA
키를 사용하여Intent.getExtras()
에서 대상 URL을 처리하는 새 활동을 생성합니다. 예를 보려면BrazeWebViewActivity.java
.- 해당 활동을
AndroidManifest.xml
에 추가하고exported
를false
로 설정합니다.1 2 3
<activity android:name=".MyCustomWebViewActivity" android:exported="false" />
BrazeConfig
빌더 객체에서 사용자 지정 활동을 설정합니다. 빌더를 빌드하여Braze.configure()
에 전달하고Application.onCreate()
.
1
2
3
4
5
BrazeConfig brazeConfig = new BrazeConfig.Builder()
.setCustomWebViewActivityClass(MyCustomWebViewActivity::class)
...
.build();
Braze.configure(this, brazeConfig);
1
2
3
4
5
val brazeConfig = BrazeConfig.Builder()
.setCustomWebViewActivityClass(MyCustomWebViewActivity::class.java)
...
.build()
Braze.configure(this, brazeConfig)
제트팩 컴포지트 사용
NavHost와 함께 젯팩 컴포즈를 사용할 때 딥링크를 처리합니다:
- 디링크를 처리하는 활동이 Android 매니페스트에 등록되어 있는지 확인하세요.
1 2 3 4 5 6 7 8 9 10 11
<activity ... <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="articles" android:scheme="myapp" /> </intent-filter> </activity>
- NavHost에서 처리할 딥링크를 지정합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
composableWithCompositionLocal( route = "YOUR_ROUTE_HERE", deepLinks = listOf(navDeepLink { uriPattern = "myapp://articles/{${MainDestinations.ARTICLE_ID_KEY}}" }), arguments = listOf( navArgument(MainDestinations.ARTICLE_ID_KEY) { type = NavType.LongType } ), ) { backStackEntry -> val arguments = requireNotNull(backStackEntry.arguments) val articleId = arguments.getLong(MainDestinations.ARTICLE_ID_KEY) ArticleDetail( articleId ) }
- 앱 아키텍처에 따라 현재 활동으로 전송되는 새 인텐트도 처리해야 할 수 있습니다.
1 2 3 4 5 6 7
DisposableEffect(Unit) { val listener = Consumer<Intent> { navHostController.handleDeepLink(it) } addOnNewIntentListener(listener) onDispose { removeOnNewIntentListener(listener) } }
Prerequisites
이 기능을 사용하려면 먼저 Swift Braze SDK를 통합해야 합니다.
Handling deep links
Step 1: Register a scheme
To handle deep linking, a custom scheme must be stated in your Info.plist
file. The navigation structure is defined by an array of dictionaries. Each of those dictionaries contains an array of strings.
Use Xcode to edit your Info.plist
file:
- Add a new key,
URL types
. Xcode will automatically make this an array containing a dictionary calledItem 0
. - Within
Item 0
, add a keyURL identifier
. Set the value to your custom scheme. - Within
Item 0
, add a keyURL Schemes
. This will automatically be an array containing aItem 0
string. - Set
URL Schemes
»Item 0
to your custom scheme.
Alternatively, if you wish to edit your Info.plist
file directly, you can follow this spec:
1
2
3
4
5
6
7
8
9
10
11
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>YOUR.SCHEME</string>
<key>CFBundleURLSchemes</key>
<array>
<string>YOUR.SCHEME</string>
</array>
</dict>
</array>
Step 2: Add a scheme allowlist
You must declare the URL schemes you wish to pass to canOpenURL(_:)
by adding the LSApplicationQueriesSchemes
key to your app’s Info.plist file. Attempting to call schemes outside this allowlist will cause the system to record an error in the device’s logs, and the deep link will not open. An example of this error will look like this:
1
<Warning>: -canOpenURL: failed for URL: "yourapp://deeplink" – error: "This app is not allowed to query for scheme yourapp"
For example, if an in-app message should open the Facebook app when tapped, the app has to have the Facebook custom scheme (fb
) in your allowlist. Otherwise, the system will reject the deep link. Deep links that direct to a page or view inside your own app still require that your app’s custom scheme be listed in your app’s Info.plist
.
Your example allowlist might look something like:
1
2
3
4
5
6
<key>LSApplicationQueriesSchemes</key>
<array>
<string>myapp</string>
<string>fb</string>
<string>twitter</string>
</array>
For more information, refer to Apple’s documentation on the LSApplicationQueriesSchemes
key.
Step 3: Implement a handler
After activating your app, iOS will call the method application:openURL:options:
. The important argument is the NSURL object.
1
2
3
4
5
6
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let path = url.path
let query = url.query
// Insert your code here to take some action based upon the path and query.
return true
}
1
2
3
4
5
6
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
NSString *path = [url path];
NSString *query = [url query];
// Insert your code here to take some action based upon the path and query.
return YES;
}
App Transport Security (ATS)
As defined by Apple, “App Transport Security is a feature that improves the security of connections between an app and web services. The feature consists of default connection requirements that conform to best practices for secure connections. Apps can override this default behavior and turn off transport security.”
ATS is applied by default. It requires that all connections use HTTPS and are encrypted using TLS 1.2 with forward secrecy. Refer to Requirements for Connecting Using ATS for more information. All images served by Braze to end devices are handled by a content delivery network (“CDN”) that supports TLS 1.2 and is compatible with ATS.
Unless they are specified as exceptions in your application’s Info.plist
, connections that do not follow these requirements will fail with errors that are similar to the following.
Example Error 1:
1
2
CFNetwork SSLHandshake failed (-9801)
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred, and a secure connection to the server cannot be made."
Example Error 2:
1
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
ATS compliance is enforced for links opened within the mobile app (our default handling of clicked links) and does not apply to sites opened externally via a web browser.
Working with ATS
You can handle ATS in either of the following ways, but we recommend complying with ATS requirements.
Your Braze integration can satisfy ATS requirements by ensuring that any existing links you drive users to (for example, though in-app message and push campaigns) satisfy ATS requirements. While there are ways to bypass ATS restrictions, our recommendation is to ensure that all linked URLs are ATS-compliant. Given Apple’s increasing emphasis on application security, the following approaches to allowing ATS exceptions are not guaranteed to be supported by Apple.
You can allow a subset of links with certain domains or schemes to be treated as exceptions to the ATS rules. Your Braze integration will satisfy ATS requirements if every link you use in a Braze messaging channel is either ATS compliant or handled by an exception.
To add a domain as an exception of the ATS, add following to your app’s Info.plist
file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
Refer to Apple’s article on app transport security keys for more information.
You can turn off ATS entirely. Note that this is not recommended practice, due to both lost security protections and future iOS compatibility. To disable ATS, insert the following in your app’s Info.plist
file:
1
2
3
4
5
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Decoding URLs
The SDK percent-encodes links to create valid URL
s. All link characters that are not allowed in a properly formed URL, such as Unicode characters, will be percent escaped.
To decode an encoded link, use the String
property removingPercentEncoding
. You must also return true
in the BrazeDelegate.braze(_:shouldOpenURL:)
. A call to action is required to trigger the handling of the URL by your app. For example:
1
2
3
4
5
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let urlString = url.absoluteString.removingPercentEncoding
// Handle urlString
return true
}
1
2
3
4
5
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options {
NSString *urlString = [url.absoluteString stringByRemovingPercentEncoding];
// Handle urlString
return YES;
}
Deep linking to app settings
You can take advantage of UIApplicationOpenSettingsURLString
to deep link users to your app’s settings from Braze push notifications, in-app messages, and the News Feed.
To take users from your app into the iOS settings:
- First, make sure your application is set up for either scheme-based deep links or universal links.
- Decide on a URI for deep linking to the Settings page (for example,
myapp://settings
orhttps://www.braze.com/settings
). - If you are using custom scheme-based deep links, add the following code to your
application:openURL:options:
method:
1
2
3
4
5
6
7
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let path = url.path
if (path == "settings") {
UIApplication.shared.openURL(URL(string:UIApplication.openSettingsURLString)!)
}
return true
}
1
2
3
4
5
6
7
8
9
10
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
NSString *path = [url path];
if ([path isEqualToString:@"settings"]) {
NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:settingsURL];
}
return YES;
}
Customization options
Default WebView customization
The Braze.WebViewController
class displays web URLs opened by the SDK, typically when “Open Web URL Inside App” is selected for a web deep link.
You can customize the Braze.WebViewController
via the BrazeDelegate.braze(_:willPresentModalWithContext:)
delegate method.
Linking handling customization
The BrazeDelegate
protocol can be used to customize the handling of URLs such as deep links, web URLs, and universal links. To set the delegate during Braze initialization, set a delegate object on the Braze
instance. Braze will then call your delegate’s implementation of shouldOpenURL
before handling any URIs.
Universal links
Braze supports universal links in push notifications, in-app messages, and Content Cards. To enable universal link support, configuration.forwardUniversalLinks
must be set to true
.
When enabled, Braze will forward universal links to your app’s AppDelegate
via the application:continueUserActivity:restorationHandler:
method.
Your application also needs to be set up to handle universal links. Refer to Apple’s documentation to ensure your application is configured correctly for universal links.
Universal link forwarding requires access to the application entitlements. When running the application in a simulator, these entitlements are not directly available and universal links are not forwarded to the system handlers.
To add support to simulator builds, you can add the application .entitlements
file to the Copy Bundle Resources build phase. See forwardUniversalLinks
documentation for more details.
The SDK does not query your domains’ apple-app-site-association
file. It performs the differentiation between universal links and regular URLs by looking at the domain name only. As a result, the SDK does not respect any exclusion rule defined in the apple-app-site-association
per Supporting associated domains.
Examples
BrazeDelegate
Here’s an example using BrazeDelegate
. For more information, see Braze Swift SDK reference.
1
2
3
4
5
6
7
8
func braze(_ braze: Braze, shouldOpenURL context: Braze.URLContext) -> Bool {
if context.url.host == "MY-DOMAIN.com" {
// Custom handle link here
return false
}
// Let Braze handle links otherwise
return true
}
1
2
3
4
5
6
7
8
- (BOOL)braze:(Braze *)braze shouldOpenURL:(BRZURLContext *)context {
if ([[context.url.host lowercaseString] isEqualToString:@"MY-DOMAIN.com"]) {
// Custom handle link here
return NO;
}
// Let Braze handle links otherwise
return YES;
}
Prerequisites
Flutter 앱에 딥링킹을 구현하려면 먼저 기본 Android 또는 iOS 레이어에서 딥링킹을 설정해야 합니다.
딥링킹 구현
1단계: Flutter의 기본 제공 처리 설정
- Xcode 프로젝트에서
Info.plist
파일을 엽니다. - 새 키-값 쌍을 추가합니다.
- 키를
FlutterDeepLinkingEnabled
로 설정합니다. - 유형을
Boolean
로 설정합니다. - 값을
YES
으로 설정합니다.
- Android Studio 프로젝트에서
AndroidManifest.xml
파일을 엽니다. activity
태그에서.MainActivity
을 찾습니다.activity
태그 안에 다음meta-data
태그를 추가합니다:1
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
2단계: Dart 레이어로 데이터 전달(선택 사항)
사용자를 앱의 특정 위치로 보내거나 특정 함수를 호출하는 등 복잡한 사용 사례에 기본, 퍼스트파티 또는 서드파티 링크 처리를 사용할 수 있습니다.
예시: 알림 대화 상자로 딥 링크하기
다음 예제에서는 추가 패키지에 의존하지 않지만 유사한 접근 방식을 사용하여 기본, 퍼스트파티 또는 서드파티 패키지(예: go_router
)를 구현할 수 있습니다. 추가 Dart 코드가 필요할 수 있습니다.
먼저 기본 레이어에서 메서드 채널을 사용하여 딥링크의 URL 문자열 데이터를 Dart 레이어로 전달합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
extension AppDelegate {
// Delegate method for handling custom scheme links.
override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
forwardURL(url)
return true
}
// Delegate method for handling universal links.
override func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else {
return false
}
forwardURL(url)
return true
}
private func forwardURL(_ url: URL) {
guard let controller: FlutterViewController = window?.rootViewController as? FlutterViewController else { return }
let deepLinkChannel = FlutterMethodChannel(name: "deepLinkChannel", binaryMessenger: controller.binaryMessenger)
deepLinkChannel.invokeMethod("receiveDeepLink", arguments: url.absoluteString)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleDeepLink(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleDeepLink(intent)
}
private fun handleDeepLink(intent: Intent) {
val binaryMessenger = flutterEngine?.dartExecutor?.binaryMessenger
if (intent?.action == Intent.ACTION_VIEW && binaryMessenger != null) {
MethodChannel(binaryMessenger, "deepLinkChannel")
.invokeMethod("receivedDeepLink", intent?.data.toString())
}
}
}
다음으로, 이전에 전송된 URL 문자열 데이터를 사용하여 경고 대화 상자를 표시하기 위해 Dart 레이어에서 콜백 함수가 사용됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MethodChannel('deepLinkChannel').setMethodCallHandler((call) async {
deepLinkAlert(call.arguments, context);
});
void deepLinkAlert(String link, BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Deep Link Alert"),
content: Text("Opened with deep link: $link"),
actions: <Widget>[
TextButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}