Files
UnrealEngine/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSharingFacebook.cpp
2025-05-18 13:04:45 +08:00

262 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
// Module includes
#include "OnlineSharingFacebook.h"
#include "OnlineSubsystemFacebookPrivate.h"
#include "OnlineIdentityFacebook.h"
#if WITH_FACEBOOK
#include "Android/AndroidJNI.h"
#include "Android/AndroidApplication.h"
#include "Async/TaskGraphInterfaces.h"
FOnlineSharingFacebook::FOnlineSharingFacebook(FOnlineSubsystemFacebook* InSubsystem)
: FOnlineSharingFacebookCommon(InSubsystem)
{
FOnFacebookRequestPermissionsOpCompleteDelegate RequestPermissionsOpDelegate = FOnFacebookRequestPermissionsOpCompleteDelegate::CreateRaw(this, &FOnlineSharingFacebook::OnPermissionsOpComplete);
OnFBRequestPermissionsOpCompleteHandle = AddOnFacebookRequestPermissionsOpCompleteDelegate_Handle(RequestPermissionsOpDelegate);
}
FOnlineSharingFacebook::~FOnlineSharingFacebook()
{
}
bool FOnlineSharingFacebook::RequestNewReadPermissions(int32 LocalUserNum, EOnlineSharingCategory NewPermissions)
{
ensure((NewPermissions & ~EOnlineSharingCategory::ReadPermissionMask) == EOnlineSharingCategory::None);
bool bTriggeredRequest = false;
bool bPendingOp = PermissionsOpCompletionDelegate.IsBound();
if (!bPendingOp)
{
IOnlineIdentityPtr IdentityInt = Subsystem->GetIdentityInterface();
if (IdentityInt.IsValid() && IdentityInt->GetLoginStatus(LocalUserNum) == ELoginStatus::LoggedIn)
{
// Here we iterate over each category, adding each individual permission linked with it in the ::SetupPermissionMaps
TArray<FSharingPermission> PermissionsNeeded;
const bool bHasPermission = CurrentPermissions.HasPermission(NewPermissions, PermissionsNeeded);
if (!bHasPermission)
{
PermissionsOpCompletionDelegate = FOnPermissionsOpComplete::CreateLambda([this, LocalUserNum](EFacebookLoginResponse InResponseCode, const FString& InAccessToken, const TArray<FString>& GrantedPermissions, const TArray<FString>& DeclinedPermissions)
{
UE_LOG_ONLINE(Display, TEXT("RequestNewReadPermissions : %s"), ToString(InResponseCode));
const bool bIsOk = (InResponseCode == EFacebookLoginResponse::RESPONSE_OK);
if (bIsOk)
{
CurrentPermissions.RefreshPermissions(GrantedPermissions, DeclinedPermissions);
}
TriggerOnRequestNewReadPermissionsCompleteDelegates(LocalUserNum, bIsOk);
});
extern bool AndroidThunkCpp_Facebook_RequestReadPermissions(const TArray<FSharingPermission>&);
bTriggeredRequest = AndroidThunkCpp_Facebook_RequestReadPermissions(PermissionsNeeded);
if (!bTriggeredRequest)
{
// Facebook SDK was not properly initialized or JEnv is wrong
OnPermissionsOpFailed();
}
}
else
{
// All permissions were already granted, no need to reauthorize
TriggerOnRequestNewReadPermissionsCompleteDelegates(LocalUserNum, true);
}
}
else
{
// If we weren't logged into Facebook we cannot do this action
TriggerOnRequestNewReadPermissionsCompleteDelegates(LocalUserNum, false);
}
}
else
{
UE_LOG_ONLINE_SHARING(Verbose, TEXT("Operation already in progress"));
TriggerOnRequestNewReadPermissionsCompleteDelegates(LocalUserNum, false);
}
return bTriggeredRequest;
}
bool FOnlineSharingFacebook::RequestNewPublishPermissions(int32 LocalUserNum, EOnlineSharingCategory NewPermissions, EOnlineStatusUpdatePrivacy Privacy)
{
ensure((NewPermissions & ~EOnlineSharingCategory::PublishPermissionMask) == EOnlineSharingCategory::None);
bool bTriggeredRequest = false;
bool bPendingOp = PermissionsOpCompletionDelegate.IsBound();
if (!bPendingOp)
{
IOnlineIdentityPtr IdentityInt = Subsystem->GetIdentityInterface();
if (IdentityInt.IsValid() && IdentityInt->GetLoginStatus(LocalUserNum) == ELoginStatus::LoggedIn)
{
// Here we iterate over each category, adding each individual permission linked with it in the ::SetupPermissionMaps
TArray<FSharingPermission> PermissionsNeeded;
const bool bHasPermission = CurrentPermissions.HasPermission(NewPermissions, PermissionsNeeded);
if (!bHasPermission)
{
PermissionsOpCompletionDelegate = FOnPermissionsOpComplete::CreateLambda([this, LocalUserNum](EFacebookLoginResponse InResponseCode, const FString& InAccessToken, const TArray<FString>& GrantedPermissions, const TArray<FString>& DeclinedPermissions)
{
UE_LOG_ONLINE(Display, TEXT("RequestNewPublishPermissions : %s"), ToString(InResponseCode));
const bool bIsOk = (InResponseCode == EFacebookLoginResponse::RESPONSE_OK);
if (bIsOk)
{
CurrentPermissions.RefreshPermissions(GrantedPermissions, DeclinedPermissions);
}
TriggerOnRequestNewPublishPermissionsCompleteDelegates(LocalUserNum, bIsOk);
});
extern bool AndroidThunkCpp_Facebook_RequestPublishPermissions(const TArray<FSharingPermission>&);
bTriggeredRequest = AndroidThunkCpp_Facebook_RequestPublishPermissions(PermissionsNeeded);
if (!bTriggeredRequest)
{
// Facebook SDK was not properly initialized or JEnv is wrong
OnPermissionsOpFailed();
}
}
else
{
// All permissions were already granted, no need to reauthorize
TriggerOnRequestNewPublishPermissionsCompleteDelegates(LocalUserNum, true);
}
}
else
{
// If we weren't logged into Facebook we cannot do this action
TriggerOnRequestNewPublishPermissionsCompleteDelegates(LocalUserNum, false);
}
}
else
{
UE_LOG_ONLINE_SHARING(Verbose, TEXT("Operation already in progress"));
TriggerOnRequestNewPublishPermissionsCompleteDelegates(LocalUserNum, false);
}
return bTriggeredRequest;
}
void FOnlineSharingFacebook::OnPermissionsOpFailed()
{
UE_LOG_ONLINE_SHARING(Verbose, TEXT("OnPermissionsOpFailed"));
PermissionsOpCompletionDelegate.ExecuteIfBound(EFacebookLoginResponse::RESPONSE_ERROR, TEXT(""), {}, {});
PermissionsOpCompletionDelegate.Unbind();
}
void FOnlineSharingFacebook::OnPermissionsOpComplete(EFacebookLoginResponse InResponseCode, const FString& InAccessToken, const TArray<FString>& GrantedPermissions, const TArray<FString>& DeclinedPermissions)
{
UE_LOG_ONLINE_SHARING(Verbose, TEXT("OnPermissionsOpComplete %s %s"), ToString(InResponseCode), *InAccessToken);
PermissionsOpCompletionDelegate.ExecuteIfBound(InResponseCode, InAccessToken, GrantedPermissions, DeclinedPermissions);
PermissionsOpCompletionDelegate.Unbind();
}
#define CHECK_JNI_METHOD(Id) checkf(Id != nullptr, TEXT("Failed to find " #Id));
bool AndroidThunkCpp_Facebook_RequestReadPermissions(const TArray<FSharingPermission>& InNewPermissions)
{
UE_LOG_ONLINE_SHARING(Verbose, TEXT("AndroidThunkCpp_Facebook_RequestReadPermissions"));
bool bSuccess = false;
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
const bool bIsOptional = false;
static jmethodID FacebookRequestReadMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Facebook_RequestReadPermissions", "([Ljava/lang/String;)Z", bIsOptional);
CHECK_JNI_METHOD(FacebookRequestReadMethod);
// Convert scope array into java fields
auto PermsIDArray = NewScopedJavaObject(Env, (jobjectArray)Env->NewObjectArray(InNewPermissions.Num(), FJavaWrapper::JavaStringClass, nullptr));
for (uint32 Param = 0; Param < InNewPermissions.Num(); Param++)
{
auto StringValue = FJavaHelper::ToJavaString(Env, InNewPermissions[Param].Name);
Env->SetObjectArrayElement(*PermsIDArray, Param, *StringValue);
}
bSuccess = FJavaWrapper::CallBooleanMethod(Env, FJavaWrapper::GameActivityThis, FacebookRequestReadMethod, *PermsIDArray);
}
return bSuccess;
}
JNI_METHOD void Java_com_epicgames_unreal_FacebookLogin_nativeRequestReadPermissionsComplete(JNIEnv* jenv, jobject thiz, jsize responseCode, jstring accessToken, jobjectArray grantedPermissions, jobjectArray declinedPermissions)
{
EFacebookLoginResponse LoginResponse = (EFacebookLoginResponse)responseCode;
auto AccessToken = FJavaHelper::FStringFromParam(jenv, accessToken);
TArray<FString> GrantedPermissions = FJavaHelper::ObjectArrayToFStringTArray(jenv, grantedPermissions);
TArray<FString> DeclinedPermissions = FJavaHelper::ObjectArrayToFStringTArray(jenv, declinedPermissions);
UE_LOG_ONLINE_SHARING(VeryVerbose, TEXT("nativeRequestReadPermissionsComplete Response: %d Token: %s"), (int)LoginResponse, *AccessToken);
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.ProcessFacebookReadPermissions"), STAT_FSimpleDelegateGraphTask_ProcessFacebookReadPermissions, STATGROUP_TaskGraphTasks);
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
FSimpleDelegateGraphTask::FDelegate::CreateLambda([=]()
{
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Facebook request read permissions completed %s\n"), ToString(LoginResponse));
if (IOnlineSubsystem* const OnlineSub = IOnlineSubsystem::Get(FACEBOOK_SUBSYSTEM))
{
FOnlineSharingFacebookPtr SharingFBInt = StaticCastSharedPtr<FOnlineSharingFacebook>(OnlineSub->GetSharingInterface());
if (SharingFBInt.IsValid())
{
SharingFBInt->TriggerOnFacebookRequestPermissionsOpCompleteDelegates(LoginResponse, AccessToken, GrantedPermissions, DeclinedPermissions);
}
}
}),
GET_STATID(STAT_FSimpleDelegateGraphTask_ProcessFacebookReadPermissions),
nullptr,
ENamedThreads::GameThread
);
}
bool AndroidThunkCpp_Facebook_RequestPublishPermissions(const TArray<FSharingPermission>& InNewPermissions)
{
UE_LOG_ONLINE_SHARING(Verbose, TEXT("AndroidThunkCpp_Facebook_RequestPublishPermissions"));
bool bSuccess = false;
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
const bool bIsOptional = false;
static jmethodID FacebookRequestPublishMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Facebook_RequestPublishPermissions", "([Ljava/lang/String;)Z", bIsOptional);
CHECK_JNI_METHOD(FacebookRequestPublishMethod);
// Convert scope array into java fields
auto PermsIDArray = NewScopedJavaObject(Env, (jobjectArray)Env->NewObjectArray(InNewPermissions.Num(), FJavaWrapper::JavaStringClass, nullptr));
for (uint32 Param = 0; Param < InNewPermissions.Num(); Param++)
{
auto StringValue = FJavaHelper::ToJavaString(Env, InNewPermissions[Param].Name);
Env->SetObjectArrayElement(*PermsIDArray, Param, *StringValue);
}
bSuccess = FJavaWrapper::CallBooleanMethod(Env, FJavaWrapper::GameActivityThis, FacebookRequestPublishMethod, *PermsIDArray);
}
return bSuccess;
}
JNI_METHOD void Java_com_epicgames_unreal_FacebookLogin_nativeRequestPublishPermissionsComplete(JNIEnv* jenv, jobject thiz, jsize responseCode, jstring accessToken, jobjectArray grantedPermissions, jobjectArray declinedPermissions)
{
EFacebookLoginResponse LoginResponse = (EFacebookLoginResponse)responseCode;
auto AccessToken = FJavaHelper::FStringFromParam(jenv, accessToken);
TArray<FString> GrantedPermissions = FJavaHelper::ObjectArrayToFStringTArray(jenv, grantedPermissions);
TArray<FString> DeclinedPermissions = FJavaHelper::ObjectArrayToFStringTArray(jenv, declinedPermissions);
UE_LOG_ONLINE_SHARING(VeryVerbose, TEXT("nativeRequestPublishPermissionsComplete Response: %d Token: %s"), (int)LoginResponse, *AccessToken);
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.ProcessFacebookPublishPermissions"), STAT_FSimpleDelegateGraphTask_ProcessFacebookPublishPermissions, STATGROUP_TaskGraphTasks);
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
FSimpleDelegateGraphTask::FDelegate::CreateLambda([=]()
{
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Facebook request publish permissions completed %s\n"), ToString(LoginResponse));
if (IOnlineSubsystem* const OnlineSub = IOnlineSubsystem::Get(FACEBOOK_SUBSYSTEM))
{
FOnlineSharingFacebookPtr SharingFBInt = StaticCastSharedPtr<FOnlineSharingFacebook>(OnlineSub->GetSharingInterface());
if (SharingFBInt.IsValid())
{
SharingFBInt->TriggerOnFacebookRequestPermissionsOpCompleteDelegates(LoginResponse, AccessToken, GrantedPermissions, DeclinedPermissions);
}
}
}),
GET_STATID(STAT_FSimpleDelegateGraphTask_ProcessFacebookPublishPermissions),
nullptr,
ENamedThreads::GameThread
);
}
#endif // WITH_FACEBOOK