Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App Links feature branch into main #102

Merged
merged 6 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# browser-switch-android Release Notes

## unreleased

* Add `appLinkUri` to `BrowserSwitchOptions` for Android App Link support

## 2.6.1

* Throw `BrowserSwitchException` when a browser is not found to start browser switch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ public void start(@NonNull FragmentActivity activity, @NonNull BrowserSwitchOpti
Uri browserSwitchUrl = browserSwitchOptions.getUrl();
int requestCode = browserSwitchOptions.getRequestCode();
String returnUrlScheme = browserSwitchOptions.getReturnUrlScheme();
Uri appLinkUri = browserSwitchOptions.getAppLinkUri();

JSONObject metadata = browserSwitchOptions.getMetadata();
BrowserSwitchRequest request =
new BrowserSwitchRequest(requestCode, browserSwitchUrl, metadata, returnUrlScheme, true);
new BrowserSwitchRequest(requestCode, browserSwitchUrl, metadata, returnUrlScheme, appLinkUri, true);
persistentStore.putActiveRequest(request, appContext);

if (activity.isFinishing()) {
Expand All @@ -76,7 +77,10 @@ public void start(@NonNull FragmentActivity activity, @NonNull BrowserSwitchOpti
}
}

void assertCanPerformBrowserSwitch(FragmentActivity activity, BrowserSwitchOptions browserSwitchOptions) throws BrowserSwitchException {
void assertCanPerformBrowserSwitch(
FragmentActivity activity,
BrowserSwitchOptions browserSwitchOptions
) throws BrowserSwitchException {
Context appContext = activity.getApplicationContext();

int requestCode = browserSwitchOptions.getRequestCode();
Expand All @@ -86,9 +90,10 @@ void assertCanPerformBrowserSwitch(FragmentActivity activity, BrowserSwitchOptio

if (!isValidRequestCode(requestCode)) {
errorMessage = activity.getString(R.string.error_request_code_invalid);
} else if (returnUrlScheme == null) {
errorMessage = activity.getString(R.string.error_return_url_required);
} else if (!browserSwitchInspector.isDeviceConfiguredForDeepLinking(appContext, returnUrlScheme)) {
} else if (returnUrlScheme == null && browserSwitchOptions.getAppLinkUri() == null) {
errorMessage = activity.getString(R.string.error_app_link_uri_or_return_url_required);
} else if (returnUrlScheme != null &&
!browserSwitchInspector.isDeviceConfiguredForDeepLinking(appContext, returnUrlScheme)) {
errorMessage = activity.getString(R.string.error_device_not_configured_for_deep_link);
}

Expand Down Expand Up @@ -162,9 +167,10 @@ public BrowserSwitchResult getResult(@NonNull FragmentActivity activity) {

BrowserSwitchResult result = null;

Uri deepLinkUrl = intent.getData();
if (deepLinkUrl != null && request.matchesDeepLinkUrlScheme(deepLinkUrl)) {
result = new BrowserSwitchResult(BrowserSwitchStatus.SUCCESS, request, deepLinkUrl);
Uri linkUrl = intent.getData();
if (linkUrl != null &&
(request.matchesDeepLinkUrlScheme(linkUrl) || request.matchesAppLinkUri(linkUrl))) {
result = new BrowserSwitchResult(BrowserSwitchStatus.SUCCESS, request, linkUrl);
} else if (request.getShouldNotifyCancellation()) {
result = new BrowserSwitchResult(BrowserSwitchStatus.CANCELED, request);
}
Expand All @@ -191,9 +197,9 @@ public BrowserSwitchResult parseResult(@NonNull Context context, int requestCode
BrowserSwitchRequest request =
persistentStore.getActiveRequest(context.getApplicationContext());
if (request != null && request.getRequestCode() == requestCode) {
Uri deepLinkUrl = intent.getData();
if (request.matchesDeepLinkUrlScheme(deepLinkUrl)) {
result = new BrowserSwitchResult(BrowserSwitchStatus.SUCCESS, request, deepLinkUrl);
Uri linkUrl = intent.getData();
if (request.matchesDeepLinkUrlScheme(linkUrl) || request.matchesAppLinkUri(linkUrl)) {
result = new BrowserSwitchResult(BrowserSwitchStatus.SUCCESS, request, linkUrl);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class BrowserSwitchOptions {
private int requestCode;
private Uri url;
private String returnUrlScheme;
private Uri appLinkUri;

private boolean launchAsNewTask;

Expand Down Expand Up @@ -68,6 +69,18 @@ public BrowserSwitchOptions returnUrlScheme(@Nullable String returnUrlScheme) {
return this;
}

/**
* Set App Link [Uri].
*
* @param appLinkUri The [Uri] containing the App Link URL used for navigating back into the application
* after browser switch
* @return {@link BrowserSwitchOptions} reference to instance to allow setter invocations to be chained
*/
public BrowserSwitchOptions appLinkUri(@Nullable Uri appLinkUri) {
this.appLinkUri = appLinkUri;
return this;
}

/**
* @return The metadata associated with the browser switch request
*/
Expand Down Expand Up @@ -99,6 +112,14 @@ public String getReturnUrlScheme() {
return returnUrlScheme;
}

/**
* @return The App Link [Uri] set for navigating back into the application after browser switch
*/
@Nullable
public Uri getAppLinkUri() {
return appLinkUri;
}

public boolean isLaunchAsNewTask() {
return launchAsNewTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,58 @@
import android.net.Uri;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;

import org.json.JSONException;
import org.json.JSONObject;

class BrowserSwitchRequest {


private final Uri url;
private final int requestCode;
private final JSONObject metadata;
private final String returnUrlScheme;
private Uri appLinkUri;
private boolean shouldNotifyCancellation;

static BrowserSwitchRequest fromJson(String json) throws JSONException {
JSONObject jsonObject = new JSONObject(json);
int requestCode = jsonObject.getInt("requestCode");
String url = jsonObject.getString("url");
String returnUrlScheme = jsonObject.getString("returnUrlScheme");
JSONObject metadata = jsonObject.optJSONObject("metadata");
Uri appLinkUri = null;
if (jsonObject.has("appLinkUri")) {
appLinkUri = Uri.parse(jsonObject.getString("appLinkUri"));
}
String returnUrlScheme = null;
if (jsonObject.has("returnUrlScheme")) {
returnUrlScheme = jsonObject.getString("returnUrlScheme");
}
boolean shouldNotify = jsonObject.optBoolean("shouldNotify", true);
return new BrowserSwitchRequest(requestCode, Uri.parse(url), metadata, returnUrlScheme, shouldNotify);
return new BrowserSwitchRequest(
requestCode,
Uri.parse(url),
metadata,
returnUrlScheme,
appLinkUri,
shouldNotify
);
}

BrowserSwitchRequest(int requestCode, Uri url, JSONObject metadata, String returnUrlScheme, boolean shouldNotifyCancellation) {
BrowserSwitchRequest(
int requestCode,
Uri url,
JSONObject metadata,
String returnUrlScheme,
Uri appLinkUri,
boolean shouldNotifyCancellation
) {
this.url = url;
this.requestCode = requestCode;
this.metadata = metadata;
this.returnUrlScheme = returnUrlScheme;
this.appLinkUri = appLinkUri;
this.shouldNotifyCancellation = shouldNotifyCancellation;
}

Expand All @@ -54,6 +78,17 @@ void setShouldNotifyCancellation(boolean shouldNotifyCancellation) {
this.shouldNotifyCancellation = shouldNotifyCancellation;
}

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Nullable
public Uri getAppLinkUri() {
return appLinkUri;
}

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void setAppLinkUri(@Nullable Uri appLinkUri) {
this.appLinkUri = appLinkUri;
}

String toJson() throws JSONException {
JSONObject result = new JSONObject();
result.put("requestCode", requestCode);
Expand All @@ -63,10 +98,19 @@ String toJson() throws JSONException {
if (metadata != null) {
result.put("metadata", metadata);
}
if (appLinkUri != null) {
result.put("appLinkUri", appLinkUri.toString());
}
return result.toString();
}

boolean matchesDeepLinkUrlScheme(@NonNull Uri url) {
return url.getScheme() != null && url.getScheme().equalsIgnoreCase(returnUrlScheme);
}

boolean matchesAppLinkUri(@NonNull Uri uri) {
return appLinkUri != null &&
uri.getScheme().equals(appLinkUri.getScheme()) &&
uri.getHost().equals(appLinkUri.getHost());
}
}
2 changes: 1 addition & 1 deletion browser-switch/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="error_request_code_invalid">Request code cannot be Integer.MIN_VALUE</string>
<string name="error_return_url_required">A returnUrlScheme is required.</string>
<string name="error_app_link_uri_or_return_url_required">An appLinkUri or returnUrlScheme is required.</string>
<string name="error_browser_not_found">No installed activities can open this URL: %1$s</string>
<string name="error_device_not_configured_for_deep_link">The return url scheme was not set up, incorrectly set up, or more than one Activity on this device defines the same url scheme in it\'s Android Manifest. See https://github.com/braintree/browser-switch-android for more information on setting up a return url scheme.</string>
</resources>
Loading
Loading