Skip to content

Commit

Permalink
fix file picker fix not working in lc2, minor change to discovering a…
Browse files Browse the repository at this point in the history
…pp group
  • Loading branch information
hugeBlack committed Jan 21, 2025
1 parent 7bcbfcc commit cb6bec8
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 19 deletions.
2 changes: 1 addition & 1 deletion LCSharedUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ + (NSString *)appGroupID {

for (NSString *group in possibleAppGroups) {
NSURL *path = [NSFileManager.defaultManager containerURLForSecurityApplicationGroupIdentifier:group];
NSURL *bundlePath = [path URLByAppendingPathComponent:@"Apps/com.kdt.livecontainer/App.app"];
NSURL *bundlePath = [path URLByAppendingPathComponent:@"Apps"];
if ([NSFileManager.defaultManager fileExistsAtPath:bundlePath.path]) {
// This will fail if LiveContainer is installed in both stores, but it should never be the case
appGroupID = group;
Expand Down
75 changes: 65 additions & 10 deletions LiveContainerSwiftUI/LCSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct LCSettingsView: View {

@StateObject private var keyChainRemovalAlert = YesNoHelper()
@StateObject private var patchAltStoreAlert = AlertHelper<PatchChoice>()
@StateObject private var installLC2Alert = AlertHelper<PatchChoice>()
@State private var isAltStorePatched = false

@StateObject private var certificateImportAlert = YesNoHelper()
Expand Down Expand Up @@ -75,7 +76,7 @@ struct LCSettingsView: View {

DataManager.shared.model.certificateImported = UserDefaults.standard.bool(forKey: "LCCertificateImported")
if !DataManager.shared.model.certificateImported {
// Only ZSign is available to ADP / Enterprise certs
// Only ZSign is available to ADP certs
_defaultSigner = State(initialValue: Signer(rawValue: LCUtils.appGroupUserDefault.integer(forKey: "LCDefaultSigner"))!)
}

Expand Down Expand Up @@ -157,7 +158,7 @@ struct LCSettingsView: View {

Section{
Button {
installAnotherLC()
Task { await installAnotherLC() }
} label: {
if sharedModel.multiLCStatus == 0 {
Text("lc.settings.multiLCInstall".loc)
Expand Down Expand Up @@ -293,7 +294,12 @@ struct LCSettingsView: View {
Button {
export()
} label: {
Text("export cert")
Text("Export Cert")
}
Button {
exportMainExecutable()
} label: {
Text("Export Main Executable")
}
} header: {
Text("Developer Settings")
Expand All @@ -309,6 +315,12 @@ struct LCSettingsView: View {
openGitHub()
}
}
HStack {
Image("GitHub")
Button("hugeBlack/LiveContainer") {
openGitHub2()
}
}
HStack {
Image("Twitter")
Button("@TranKha50277352") {
Expand Down Expand Up @@ -385,7 +397,7 @@ struct LCSettingsView: View {
Button(role: .destructive) {
patchAltStoreAlert.close(result: .autoPath)
} label: {
Text("lc.common.ok".loc)
Text("lc.common.continue".loc)
}
if(isSideStore) {
Button {
Expand All @@ -407,6 +419,25 @@ struct LCSettingsView: View {
}

}
.alert("lc.settings.multiLCInstall".loc, isPresented: $installLC2Alert.show) {
Button {
installLC2Alert.close(result: .autoPath)
} label: {
Text("lc.common.continue".loc)
}
if(isSideStore) {
Button {
installLC2Alert.close(result: .archiveOnly)
} label: {
Text("lc.settings.patchStoreArchiveOnly".loc)
}
}
Button("lc.common.cancel".loc, role: .cancel) {
patchAltStoreAlert.close(result: .cancel)
}
} message: {
Text("lc.settings.multiLCInstallAlertDesc %@".localizeWithFormat(storeName))
}
.alert("lc.settings.importCertificate".loc, isPresented: $certificateImportAlert.show) {
Button {
certificateImportAlert.close(result: true)
Expand Down Expand Up @@ -498,21 +529,28 @@ struct LCSettingsView: View {
LCUtils.appGroupUserDefault.setValue(val, forKey: key)
}

func installAnotherLC() {
func installAnotherLC() async {
if !LCUtils.isAppGroupAltStoreLike() {
errorInfo = "lc.settings.unsupportedInstallMethod".loc
errorShow = true
return;
}
let password = LCUtils.certificatePassword()
let lcDomain = UserDefaults.init(suiteName: LCUtils.appGroupID())
lcDomain?.setValue(password, forKey: "LCCertificatePassword")

guard let result = await installLC2Alert.open(), result != .cancel else {
return
}

do {
let packedIpaUrl = try LCUtils.archiveIPA(withBundleName: "LiveContainer2")
let storeInstallUrl = String(format: LCUtils.storeInstallURLScheme(), packedIpaUrl.absoluteString)
UIApplication.shared.open(URL(string: storeInstallUrl)!)
if result == .archiveOnly {
let movedAltStoreIpaUrl = LCPath.docPath.appendingPathComponent("LiveContainer2.ipa")
try FileManager.default.moveItem(at: packedIpaUrl, to: movedAltStoreIpaUrl)
successInfo = "lc.settings.multiLCArchiveSuccess".loc
successShow = true
} else {
let storeInstallUrl = String(format: LCUtils.storeInstallURLScheme(), packedIpaUrl.absoluteString)
await UIApplication.shared.open(URL(string: storeInstallUrl)!)
}
} catch {
errorInfo = error.localizedDescription
errorShow = true
Expand Down Expand Up @@ -701,6 +739,10 @@ struct LCSettingsView: View {
UIApplication.shared.open(URL(string: "https://github.com/khanhduytran0/LiveContainer")!)
}

func openGitHub2() {
UIApplication.shared.open(URL(string: "https://github.com/hugeBlack/LiveContainer")!)
}

func openTwitter() {
UIApplication.shared.open(URL(string: "https://twitter.com/TranKha50277352")!)
}
Expand Down Expand Up @@ -795,6 +837,19 @@ struct LCSettingsView: View {
}
}

func exportMainExecutable() {
let url = Bundle.main.executableURL!
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
let destinationURL = documentsURL.appendingPathComponent(url.lastPathComponent)
try fileManager.copyItem(at: url, to: destinationURL)
print("Successfully copied main executable to Documents.")
} catch {
print("Error copying main executable \(error)")
}
}

func importCertificate() async {
guard let doImport = await certificateImportAlert.open(), doImport else {
return
Expand Down
57 changes: 54 additions & 3 deletions LiveContainerSwiftUI/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@
"zh_CN" : {
"stringUnit" : {
"state" : "translated",
"value" : "将App转换为共享App以在LiveContainer中使用"
"value" : "将App转换为共享App以在LiveContainer2中使用"
}
}
}
Expand Down Expand Up @@ -1266,6 +1266,23 @@
}
}
},
"lc.common.continue" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Continue"
}
},
"zh_CN" : {
"stringUnit" : {
"state" : "translated",
"value" : "继续"
}
}
}
},
"lc.common.copy" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -2972,6 +2989,23 @@
}
}
},
"lc.settings.multiLCArchiveSuccess" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The packed second LiveContainer has been saved to LiveContainer's document folder. Please install it manually."
}
},
"zh_CN" : {
"stringUnit" : {
"state" : "translated",
"value" : "打包的第二个LiveContainer ipa已经保存到LiveContainer的“文件”文件夹,请将其手动安装。"
}
}
}
},
"lc.settings.multiLCDesc" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -3006,6 +3040,23 @@
}
}
},
"lc.settings.multiLCInstallAlertDesc %@" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ will be opened to install the second LiveContainer, Continue?\\n\\nSelect “Archive Only” if you want to do some customization and install manually."
}
},
"zh_CN" : {
"stringUnit" : {
"state" : "translated",
"value" : "即将跳转到%@来安装第二个LiveContainer,要继续吗? 可选择“仅打包”来进行自定义并手动安装。"
}
}
}
},
"lc.settings.multiLCIsSecond" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -3114,13 +3165,13 @@
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Patched %@ has been saved to LiveContainer's document folder. Please install it with the %@ that LiveContainer is installed with."
"value" : "Patched %@ ipa has been saved to LiveContainer's document folder. Please install it with the %@ that LiveContainer is installed with."
}
},
"zh_CN" : {
"stringUnit" : {
"state" : "translated",
"value" : "打包的%@已经保存到LiveContainer的“文件”文件夹,请将其手动安装到安装了LiveContainer的那个%@中。"
"value" : "打包的%@ ipa已经保存到LiveContainer的“文件”文件夹,请将其手动安装到安装了LiveContainer的那个%@中。"
}
}
}
Expand Down
22 changes: 17 additions & 5 deletions main.m
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,30 @@ static void overwriteExecPath(NSString *bundlePath) {
NSURL *appGroupFolder = nil;

NSString *bundlePath = [NSString stringWithFormat:@"%@/Applications/%@", docPath, selectedApp];
NSBundle *appBundle = [[NSBundle alloc] initWithPath:bundlePath];
guestAppInfo = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/LCAppInfo.plist", bundlePath]];
bool isSharedBundle = false;
// not found locally, let's look for the app in shared folder
if (!appBundle) {
if(!guestAppInfo) {
NSURL *appGroupPath = [NSFileManager.defaultManager containerURLForSecurityApplicationGroupIdentifier:[LCSharedUtils appGroupID]];
appGroupFolder = [appGroupPath URLByAppendingPathComponent:@"LiveContainer"];

bundlePath = [NSString stringWithFormat:@"%@/Applications/%@", appGroupFolder.path, selectedApp];
appBundle = [[NSBundle alloc] initWithPath:bundlePath];
guestAppInfo = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/LCAppInfo.plist", bundlePath]];
isSharedBundle = true;
}
guestAppInfo = [NSDictionary dictionaryWithContentsOfURL:[appBundle URLForResource:@"LCAppInfo" withExtension:@"plist"]];

if(!guestAppInfo) {
return @"Unable to read LCAppInfo.plist";
}

if([guestAppInfo[@"doUseLCBundleId"] boolValue] ) {
NSMutableDictionary* infoPlist = [NSMutableDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", bundlePath]];
if(![infoPlist[@"CFBundleIdentifier"] isEqualToString:NSBundle.mainBundle.bundleIdentifier]) {
infoPlist[@"CFBundleIdentifier"] = NSBundle.mainBundle.bundleIdentifier;
[infoPlist writeToFile:[NSString stringWithFormat:@"%@/Info.plist", bundlePath] atomically:YES];
}
}

NSBundle *appBundle = [[NSBundle alloc] initWithPath:bundlePath];

if(!appBundle) {
return @"App not found";
Expand Down

0 comments on commit cb6bec8

Please sign in to comment.