You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Moved some Android settings to ProjectSettings, re-enabled SDK settings - Removed SigningConfig.xml, and moved those settings into project settings - Added concept of NotForLicensees and NoRedist engine and project config settings - Removed BaseInternalGame.ini, replaced with NotForLicensees/BaseGame.ini - Moved User*.ini to end of .ini hierarchy - Added support for CLASS_GlobalUserConfig, so their settings will be saved to <AppData>/.../User*.ini (useful for SDK paths, etc) - Enabled AndroidPlatformEditor module on Mac - Changed Mac Build.sh to allow for Android on the commandline (just pass through if it's not an Xcode platform name) - Iterative Android packaging now looks at just the important .ini sections, NOT entire .ini files #codereview jamie.dale,james.moran,michael.trepka,robert.jones,chris.babcock [CL 2413870 by Josh Adams in Main branch]
301 lines
12 KiB
C++
301 lines
12 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "AndroidPlatformEditorPrivatePCH.h"
|
|
#include "AndroidTargetSettingsCustomization.h"
|
|
#include "DetailLayoutBuilder.h"
|
|
#include "DetailCategoryBuilder.h"
|
|
#include "PropertyEditing.h"
|
|
|
|
#include "ScopedTransaction.h"
|
|
#include "SExternalImageReference.h"
|
|
#include "SHyperlinkLaunchURL.h"
|
|
#include "SPlatformSetupMessage.h"
|
|
#include "PlatformIconInfo.h"
|
|
#include "SourceControlHelpers.h"
|
|
#include "ManifestUpdateHelper.h"
|
|
#include "SNotificationList.h"
|
|
#include "NotificationManager.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "AndroidRuntimeSettings"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FAndroidTargetSettingsCustomization
|
|
namespace FAndroidTargetSettingsCustomizationConstants
|
|
{
|
|
const FText DisabledTip = LOCTEXT("GitHubSourceRequiredToolTip", "This requires GitHub source.");
|
|
}
|
|
|
|
TSharedRef<IDetailCustomization> FAndroidTargetSettingsCustomization::MakeInstance()
|
|
{
|
|
return MakeShareable(new FAndroidTargetSettingsCustomization);
|
|
}
|
|
|
|
FAndroidTargetSettingsCustomization::FAndroidTargetSettingsCustomization()
|
|
: AndroidRelativePath(TEXT(""))
|
|
, EngineAndroidPath(FPaths::EngineDir() + TEXT("Build/Android/Java"))
|
|
, GameAndroidPath(FPaths::GameDir() + TEXT("Build/Android"))
|
|
, EngineGooglePlayAppIDPath(EngineAndroidPath / TEXT("res") / TEXT("values") / TEXT("GooglePlayAppID.xml"))
|
|
, GameGooglePlayAppIDPath(GameAndroidPath / TEXT("res") / TEXT("values") / TEXT("GooglePlayAppID.xml"))
|
|
, EngineProguardPath(EngineAndroidPath / TEXT("proguard-project.txt"))
|
|
, GameProguardPath(GameAndroidPath / TEXT("proguard-project.txt"))
|
|
, EngineProjectPropertiesPath(EngineAndroidPath / TEXT("project.properties"))
|
|
, GameProjectPropertiesPath(GameAndroidPath / TEXT("project.properties"))
|
|
{
|
|
new (IconNames) FPlatformIconInfo(TEXT("res/drawable/icon.png"), LOCTEXT("SettingsIcon", "Icon"), FText::GetEmpty(), 48, 48, FPlatformIconInfo::Required);
|
|
new (IconNames) FPlatformIconInfo(TEXT("res/drawable-ldpi/icon.png"), LOCTEXT("SettingsIcon_LDPI", "LDPI Icon"), FText::GetEmpty(), 36, 36, FPlatformIconInfo::Required);
|
|
new (IconNames) FPlatformIconInfo(TEXT("res/drawable-mdpi/icon.png"), LOCTEXT("SettingsIcon_MDPI", "MDPI Icon"), FText::GetEmpty(), 48, 48, FPlatformIconInfo::Required);
|
|
new (IconNames) FPlatformIconInfo(TEXT("res/drawable-hdpi/icon.png"), LOCTEXT("SettingsIcon_HDPI", "HDPI Icon"), FText::GetEmpty(), 72, 72, FPlatformIconInfo::Required);
|
|
new (IconNames) FPlatformIconInfo(TEXT("res/drawable-xhdpi/icon.png"), LOCTEXT("SettingsIcon_XHDPI", "XHDPI Icon"), FText::GetEmpty(), 96, 96, FPlatformIconInfo::Required);
|
|
}
|
|
|
|
void FAndroidTargetSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailLayout)
|
|
{
|
|
SavedLayoutBuilder = &DetailLayout;
|
|
|
|
BuildAppManifestSection(DetailLayout);
|
|
BuildIconSection(DetailLayout);
|
|
}
|
|
|
|
void FAndroidTargetSettingsCustomization::BuildAppManifestSection(IDetailLayoutBuilder& DetailLayout)
|
|
{
|
|
// Cache some categories
|
|
IDetailCategoryBuilder& APKPackagingCategory = DetailLayout.EditCategory(TEXT("APKPackaging"));
|
|
IDetailCategoryBuilder& BuildCategory = DetailLayout.EditCategory(TEXT("Build"));
|
|
IDetailCategoryBuilder& SigningCategory = DetailLayout.EditCategory(TEXT("DistributionSigning"));
|
|
|
|
TSharedRef<SPlatformSetupMessage> PlatformSetupMessage = SNew(SPlatformSetupMessage, GameProjectPropertiesPath)
|
|
.PlatformName(LOCTEXT("AndroidPlatformName", "Android"))
|
|
.OnSetupClicked(this, &FAndroidTargetSettingsCustomization::CopySetupFilesIntoProject);
|
|
|
|
SetupForPlatformAttribute = PlatformSetupMessage->GetReadyToGoAttribute();
|
|
|
|
APKPackagingCategory.AddCustomRow(LOCTEXT("Warning", "Warning"), false)
|
|
.WholeRowWidget
|
|
[
|
|
PlatformSetupMessage
|
|
];
|
|
|
|
APKPackagingCategory.AddCustomRow(LOCTEXT("BuildFolderLabel", "Build Folder"), false)
|
|
.IsEnabled(SetupForPlatformAttribute)
|
|
.NameContent()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(FMargin(0, 1, 0, 1))
|
|
.FillWidth(1.0f)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("BuildFolderLabel", "Build Folder"))
|
|
.Font(DetailLayout.GetDetailFont())
|
|
]
|
|
]
|
|
.ValueContent()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew(SButton)
|
|
.Text(LOCTEXT("OpenBuildFolderButton", "Open Build Folder"))
|
|
.ToolTipText(LOCTEXT("OpenManifestFolderButton_Tooltip", "Opens the folder containing the build files in Explorer or Finder (it's recommended you check these in to source control to share with your team)"))
|
|
.OnClicked(this, &FAndroidTargetSettingsCustomization::OpenBuildFolder)
|
|
]
|
|
];
|
|
|
|
// Signing category
|
|
SigningCategory.AddCustomRow(LOCTEXT("SigningHyperlink", "Signing Hyperlink"), false)
|
|
.WholeRowWidget
|
|
[
|
|
SNew(SBox)
|
|
.HAlign(HAlign_Center)
|
|
[
|
|
SNew(SHyperlinkLaunchURL, TEXT("http://developer.android.com/tools/publishing/app-signing.html#releasemode"))
|
|
.Text(LOCTEXT("AndroidDeveloperSigningPage", "Android Developer page on Signing for Distribution"))
|
|
.ToolTipText(LOCTEXT("AndroidDeveloperSigningPageTooltip", "Opens a page that discusses the signing using keytool"))
|
|
]
|
|
];
|
|
|
|
// Google Play category
|
|
IDetailCategoryBuilder& GooglePlayCategory = DetailLayout.EditCategory(TEXT("GooglePlayServices"));
|
|
|
|
TSharedRef<SPlatformSetupMessage> GooglePlaySetupMessage = SNew(SPlatformSetupMessage, GameGooglePlayAppIDPath)
|
|
.PlatformName(LOCTEXT("GooglePlayPlatformName", "Google Play services"))
|
|
.OnSetupClicked(this, &FAndroidTargetSettingsCustomization::CopyGooglePlayAppIDFileIntoProject);
|
|
|
|
SetupForGooglePlayAttribute = GooglePlaySetupMessage->GetReadyToGoAttribute();
|
|
|
|
GooglePlayCategory.AddCustomRow(LOCTEXT("Warning", "Warning"), false)
|
|
.WholeRowWidget
|
|
[
|
|
GooglePlaySetupMessage
|
|
];
|
|
|
|
GooglePlayCategory.AddCustomRow(LOCTEXT("AppIDHyperlink", "App ID Hyperlink"), false)
|
|
.WholeRowWidget
|
|
[
|
|
SNew(SBox)
|
|
.HAlign(HAlign_Center)
|
|
[
|
|
SNew(SHyperlinkLaunchURL, TEXT("http://developer.android.com/google/index.html"))
|
|
.Text(LOCTEXT("GooglePlayDeveloperPage", "Android Developer Page on Google Play services"))
|
|
.ToolTipText(LOCTEXT("GooglePlayDeveloperPageTooltip", "Opens a page that discusses Google Play services"))
|
|
]
|
|
];
|
|
|
|
TSharedRef<IPropertyHandle> EnabledProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UAndroidRuntimeSettings, bEnableGooglePlaySupport));
|
|
GooglePlayCategory.AddProperty(EnabledProperty)
|
|
.EditCondition(SetupForGooglePlayAttribute, NULL);
|
|
|
|
TSharedRef<IPropertyHandle> AppIDProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UAndroidRuntimeSettings, GamesAppID));
|
|
AppIDProperty->SetOnPropertyValueChanged(FSimpleDelegate::CreateRaw(this, &FAndroidTargetSettingsCustomization::OnAppIDModified));
|
|
GooglePlayCategory.AddProperty(AppIDProperty)
|
|
.EditCondition(SetupForGooglePlayAttribute, NULL);
|
|
|
|
TSharedRef<IPropertyHandle> AdMobAdUnitIDProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UAndroidRuntimeSettings, AdMobAdUnitID));
|
|
GooglePlayCategory.AddProperty(AdMobAdUnitIDProperty)
|
|
.EditCondition(SetupForGooglePlayAttribute, NULL);
|
|
|
|
TSharedRef<IPropertyHandle> GooglePlayLicenseKeyProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UAndroidRuntimeSettings, GooglePlayLicenseKey));
|
|
GooglePlayCategory.AddProperty(GooglePlayLicenseKeyProperty)
|
|
.EditCondition(SetupForGooglePlayAttribute, NULL);
|
|
|
|
|
|
#define SETUP_NONROCKET_PROP(PropName, Category, Tip) \
|
|
{ \
|
|
TSharedRef<IPropertyHandle> PropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UAndroidRuntimeSettings, PropName)); \
|
|
Category.AddProperty(PropertyHandle) \
|
|
.EditCondition(SetupForPlatformAttribute, NULL) \
|
|
.IsEnabled(!FRocketSupport::IsRocket()) \
|
|
.ToolTip(!FRocketSupport::IsRocket() ? Tip : FAndroidTargetSettingsCustomizationConstants::DisabledTip); \
|
|
}
|
|
SETUP_NONROCKET_PROP(bBuildForArmV7, BuildCategory, LOCTEXT("BuildForArmV7ToolTip", "Enable ArmV7 CPU architecture support? (this will be used if all CPU architecture types are unchecked)"));
|
|
SETUP_NONROCKET_PROP(bBuildForX86, BuildCategory, LOCTEXT("BuildForX86ToolTip", "Enable X86 CPU architecture support?"));
|
|
SETUP_NONROCKET_PROP(bBuildForES2, BuildCategory, LOCTEXT("BuildForES2ToolTip", "Enable OpenGL ES2 rendering support? (this will be used if rendering types are unchecked)"));
|
|
SETUP_NONROCKET_PROP(bBuildForES31, BuildCategory, LOCTEXT("BuildForES31ToolTip", "Enable OpenGL ES31 + AEP (Android Extension Pack) rendering support?"));
|
|
// @todo android fat binary: Put back in when we expose those
|
|
// SETUP_NONROCKET_PROP(bSplitIntoSeparateApks, BuildCategory, LOCTEXT("SplitIntoSeparateAPKsToolTip", "If checked, CPU architectures and rendering types will be split into separate .apk files"));
|
|
}
|
|
|
|
void FAndroidTargetSettingsCustomization::BuildIconSection(IDetailLayoutBuilder& DetailLayout)
|
|
{
|
|
// Icon category
|
|
IDetailCategoryBuilder& IconCategory = DetailLayout.EditCategory(TEXT("Icons"));
|
|
|
|
IconCategory.AddCustomRow(LOCTEXT("IconsHyperlink", "Icons Hyperlink"), false)
|
|
.WholeRowWidget
|
|
[
|
|
SNew(SBox)
|
|
.HAlign(HAlign_Center)
|
|
[
|
|
SNew(SHyperlinkLaunchURL, TEXT("http://developer.android.com/design/style/iconography.html"))
|
|
.Text(LOCTEXT("AndroidDeveloperIconographyPage", "Android Developer Page on Iconography"))
|
|
.ToolTipText(LOCTEXT("AndroidDeveloperIconographyPageTooltip", "Opens a page on Android Iconography"))
|
|
]
|
|
];
|
|
|
|
for (const FPlatformIconInfo& Info : IconNames)
|
|
{
|
|
const FString AutomaticImagePath = EngineAndroidPath / Info.IconPath;
|
|
const FString TargetImagePath = GameAndroidPath / Info.IconPath;
|
|
|
|
IconCategory.AddCustomRow(Info.IconName)
|
|
.NameContent()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.Padding( FMargin( 0, 1, 0, 1 ) )
|
|
.FillWidth(1.0f)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(Info.IconName)
|
|
.Font(DetailLayout.GetDetailFont())
|
|
]
|
|
]
|
|
.ValueContent()
|
|
.MaxDesiredWidth(400.0f)
|
|
.MinDesiredWidth(100.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SExternalImageReference, AutomaticImagePath, TargetImagePath)
|
|
.FileDescription(Info.IconDescription)
|
|
.RequiredSize(Info.IconRequiredSize)
|
|
.MaxDisplaySize(FVector2D(Info.IconRequiredSize))
|
|
]
|
|
];
|
|
}
|
|
}
|
|
|
|
FReply FAndroidTargetSettingsCustomization::OpenBuildFolder()
|
|
{
|
|
const FString BuildFolder = FPaths::ConvertRelativePathToFull(FPaths::GetPath(GameProjectPropertiesPath));
|
|
FPlatformProcess::ExploreFolder(*BuildFolder);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
void FAndroidTargetSettingsCustomization::CopySetupFilesIntoProject()
|
|
{
|
|
// First copy the manifest, it must get copied
|
|
FText ErrorMessage;
|
|
if (!SourceControlHelpers::CopyFileUnderSourceControl(GameProjectPropertiesPath, EngineProjectPropertiesPath, LOCTEXT("ProjectProperties", "Project Properties"), /*out*/ ErrorMessage))
|
|
{
|
|
FNotificationInfo Info(ErrorMessage);
|
|
Info.ExpireDuration = 3.0f;
|
|
FSlateNotificationManager::Get().AddNotification(Info);
|
|
}
|
|
else
|
|
{
|
|
// Now try to copy all of the icons, etc... (these can be ignored if the file already exists)
|
|
for (const FPlatformIconInfo& Info : IconNames)
|
|
{
|
|
const FString EngineImagePath = EngineAndroidPath / Info.IconPath;
|
|
const FString ProjectImagePath = GameAndroidPath / Info.IconPath;
|
|
|
|
if (!FPaths::FileExists(ProjectImagePath))
|
|
{
|
|
SourceControlHelpers::CopyFileUnderSourceControl(ProjectImagePath, EngineImagePath, Info.IconName, /*out*/ ErrorMessage);
|
|
}
|
|
}
|
|
|
|
// and copy the other files (aren't required)
|
|
SourceControlHelpers::CopyFileUnderSourceControl(GameProguardPath, EngineProguardPath, LOCTEXT("Proguard", "Proguard Settings"), /*out*/ ErrorMessage);
|
|
}
|
|
|
|
SavedLayoutBuilder->ForceRefreshDetails();
|
|
}
|
|
|
|
void FAndroidTargetSettingsCustomization::CopyGooglePlayAppIDFileIntoProject()
|
|
{
|
|
FText ErrorMessage;
|
|
if (!SourceControlHelpers::CopyFileUnderSourceControl(GameGooglePlayAppIDPath, EngineGooglePlayAppIDPath, LOCTEXT("GooglePlayAppID", "GooglePlayAppID.xml"), /*out*/ ErrorMessage))
|
|
{
|
|
FNotificationInfo Info(ErrorMessage);
|
|
Info.ExpireDuration = 3.0f;
|
|
FSlateNotificationManager::Get().AddNotification(Info);
|
|
}
|
|
|
|
SavedLayoutBuilder->ForceRefreshDetails();
|
|
}
|
|
|
|
void FAndroidTargetSettingsCustomization::OnAppIDModified()
|
|
{
|
|
check(SetupForPlatformAttribute.Get() == true);
|
|
|
|
|
|
FManifestUpdateHelper Updater(GameGooglePlayAppIDPath);
|
|
|
|
const FString AppIDTag(TEXT("name=\"app_id\">"));
|
|
const FString ClosingTag(TEXT("</string>"));
|
|
const FString NewIDString = GetDefault<UAndroidRuntimeSettings>()->GamesAppID;
|
|
Updater.ReplaceKey(AppIDTag, ClosingTag, NewIDString);
|
|
|
|
Updater.Finalize(GameGooglePlayAppIDPath);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#undef LOCTEXT_NAMESPACE |