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

feat: add android custom tabs dismiss listener for pkce flow #33

Merged
merged 1 commit into from
Oct 30, 2023
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
17 changes: 17 additions & 0 deletions Source/Immutable/Immutable_UPL_Android.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@
</intent>
</addElements>
</androidManifestUpdates>
<gameActivityImportAdditions>
<insert>
import com.immutable.unreal.ImmutableAndroid;
</insert>
</gameActivityImportAdditions>
<gameActivityImplementsAdditions>
<insert>
ImmutableAndroid.Callback,
</insert>
</gameActivityImplementsAdditions>
<gameActivityOnCreateAdditions>
<insert>
Uri uri = getIntent().getData();
Expand All @@ -44,6 +54,13 @@
<gameActivityClassAdditions>
<insert>
public native void handleDeepLink(String Deeplink);

public native void handleOnCustomTabsDismissed();

@Override
public void onCustomTabsDismissed() {
handleOnCustomTabsDismissed();
}
</insert>
</gameActivityClassAdditions>
<buildGradleAdditions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,10 @@ Java_com_epicgames_unreal_GameActivity_handleDeepLink(JNIEnv *env, jobject obj,
UImmutablePassport::HandleDeepLink(deeplink);
env->ReleaseStringUTFChars(jDeeplink, deeplinkCStr);
}

JNI_METHOD void
Java_com_epicgames_unreal_GameActivity_handleOnCustomTabsDismissed(
JNIEnv *env, jobject obj) {
UImmutablePassport::HandleCustomTabsDismissed();
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ extern "C" {
JNI_METHOD void Java_com_epicgames_unreal_GameActivity_handleDeepLink(JNIEnv *,
jobject,
jstring);

JNI_METHOD void
Java_com_epicgames_unreal_GameActivity_handleOnCustomTabsDismissed(JNIEnv *,
jobject);
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
import android.graphics.Insets;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.WindowInsets;
import android.view.WindowMetrics;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsCallback;
import androidx.browser.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsIntent;
Expand Down Expand Up @@ -68,7 +70,14 @@ public void onServiceDisconnected(ComponentName name) {

@Override
public void onCustomTabsServiceConnected(@NonNull ComponentName name, @NonNull CustomTabsClient client) {
CustomTabsSession session = client.newSession(new CustomTabsCallback());
CustomTabsSession session = client.newSession(new CustomTabsCallback() {
@Override
public void onNavigationEvent(int navigationEvent, @Nullable Bundle extras) {
if (context instanceof Callback && navigationEvent == CustomTabsCallback.TAB_HIDDEN) {
((Callback) context).onCustomTabsDismissed();
}
}
});
// Need to set the session to get custom tabs to show as a bottom sheet
CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder(session)
.setInitialActivityHeightPx(getCustomTabsHeight(context))
Expand All @@ -84,4 +93,8 @@ public void onCustomTabsServiceConnected(@NonNull ComponentName name, @NonNull C
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
}
}

public interface Callback {
void onCustomTabsDismissed();
}
}
45 changes: 45 additions & 0 deletions Source/Immutable/Private/Immutable/ImmutablePassport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ void UImmutablePassport::ConfirmCode(
#if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC
void UImmutablePassport::ConnectPKCE(
const FImtblPassportResponseDelegate &ResponseDelegate) {
#if PLATFORM_ANDROID
completingPKCE = false;
#endif

PKCEResponseDelegate = ResponseDelegate;
CallJS(ImmutablePassportAction::GetPKCEAuthUrl, TEXT(""),
PKCEResponseDelegate,
Expand Down Expand Up @@ -487,6 +491,9 @@ void UImmutablePassport::OnGetPKCEAuthUrlResponse(FImtblJSResponse Response) {
Msg = Response.JsonObject->GetStringField(TEXT("result"))
.Replace(TEXT(" "), TEXT("+"));
#if PLATFORM_ANDROID
OnPKCEDismissed = FImtblPassportOnPKCEDismissedDelegate::CreateUObject(
this, &UImmutablePassport::HandleOnPKCEDismissed);

JNIEnv *Env = FAndroidApplication::GetJavaEnv();
if (Env) {
jstring jurl = Env->NewStringUTF(TCHAR_TO_UTF8(*Msg));
Expand Down Expand Up @@ -539,6 +546,9 @@ void UImmutablePassport::OnConnectPKCEResponse(FImtblJSResponse Response) {
} else {
IMTBL_ERR("Unable to return a response for Connect PKCE");
}
#if PLATFORM_ANDROID
completingPKCE = false;
#endif
}
#endif

Expand Down Expand Up @@ -737,6 +747,10 @@ void UImmutablePassport::OnDeepLinkActivated(FString DeepLink) {
}

void UImmutablePassport::CompletePKCEFlow(FString Url) {
#if PLATFORM_ANDROID
completingPKCE = true;
#endif

// Get code and state from deeplink URL
TOptional<FString> Code, State;
FString Endpoint, Params;
Expand All @@ -761,6 +775,9 @@ void UImmutablePassport::CompletePKCEFlow(FString Url) {
PKCEResponseDelegate.ExecuteIfBound(
FImmutablePassportResult{false, ErrorMsg});
PKCEResponseDelegate = nullptr;
#if PLATFORM_ANDROID
completingPKCE = false;
#endif
} else {
FImmutablePassportConnectPKCEData Data =
FImmutablePassportConnectPKCEData{Code.GetValue(), State.GetValue()};
Expand Down Expand Up @@ -790,6 +807,34 @@ void UImmutablePassport::HandleDeepLink(NSString *sDeepLink) {
#endif

#if PLATFORM_ANDROID
void UImmutablePassport::HandleOnPKCEDismissed() {
IMTBL_LOG("Handle On PKCE Dismissed");
FFunctionGraphTask::CreateAndDispatchWhenReady(
[=]() {
OnPKCEDismissed = nullptr;
if (!completingPKCE) {
// User hasn't entered all required details (e.g. email address) into
// Passport yet
IMTBL_LOG("PKCE dismissed before completing the flow");
if (!PKCEResponseDelegate.ExecuteIfBound(
FImmutablePassportResult{false, "Cancelled"})) {
IMTBL_WARN("PKCEResponseDelegate delegate was not called");
}
PKCEResponseDelegate = nullptr;
} else {
IMTBL_LOG("PKCE dismissed by user or SDK");
}
},
TStatId(), nullptr, ENamedThreads::GameThread);
}

void UImmutablePassport::HandleCustomTabsDismissed() {
IMTBL_LOG("On PKCE Dismissed");
if (!OnPKCEDismissed.ExecuteIfBound()) {
IMTBL_WARN("OnPKCEDismissed delegate was not called");
}
}

void UImmutablePassport::CallJniStaticVoidMethod(JNIEnv *Env,
const jclass Class,
jmethodID Method, ...) {
Expand Down
10 changes: 10 additions & 0 deletions Source/Immutable/Public/Immutable/ImmutablePassport.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,10 @@ struct FImmutablePassportConnectPKCEData {
DECLARE_DELEGATE_OneParam(FImtblPassportHandleDeepLinkDelegate, FString);
FImtblPassportHandleDeepLinkDelegate OnHandleDeepLink;
#endif
#if PLATFORM_ANDROID
DECLARE_DELEGATE(FImtblPassportOnPKCEDismissedDelegate);
FImtblPassportOnPKCEDismissedDelegate OnPKCEDismissed;
#endif

/**
*
Expand All @@ -418,6 +422,7 @@ class IMMUTABLE_API UImmutablePassport : public UObject {

#if PLATFORM_ANDROID
static void HandleDeepLink(FString DeepLink);
static void HandleCustomTabsDismissed();
#elif PLATFORM_IOS | PLATFORM_MAC
static void HandleDeepLink(NSString *sDeepLink);
#endif
Expand Down Expand Up @@ -503,6 +508,10 @@ class IMMUTABLE_API UImmutablePassport : public UObject {
bool bIsInitialized = false;
bool bIsLoggedIn = false;

#if PLATFORM_ANDROID
bool completingPKCE = false; // Used for the PKCE callback
#endif

TWeakObjectPtr<UImtblJSConnector> JSConnector;
FImmutablePassportInitData InitData;
FDelegateHandle BridgeReadyHandle;
Expand Down Expand Up @@ -557,6 +566,7 @@ class IMMUTABLE_API UImmutablePassport : public UObject {
#endif

#if PLATFORM_ANDROID
void HandleOnPKCEDismissed();
void CallJniStaticVoidMethod(JNIEnv *Env, const jclass Class,
jmethodID Method, ...);
#endif
Expand Down
Loading