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

Unable to handle application bundles zipped with a parent directory #32

Open
natmark opened this issue Nov 12, 2024 · 4 comments
Open

Comments

@natmark
Copy link

natmark commented Nov 12, 2024

Description

The application bundle(.app format) has a directory structure, so I stored it in cloud storage as a zip archived file.
I want to use a hosted application bundle in .zip format, like http://localhost:29070/install/ios?virtual=https://#{host}/#{path}/myapp.app.zip, in Tophat. However, due to an incorrect unpacked path, installation fails.

Steps to reproduce

  1. Prepare an application bundle like myapp.app.
  2. Compress myapp.app into a zip archive named myapp.app.zip.
  3. Request http://localhost:29070/install/ios?virtual=file:///path/to/myapp.app.zip

Expected behavior

It should be possible to install an application bundle that has been archived in zip format.

Screenshots

Image

System

  • Device: MacBook Pro
  • OS: macOS 14.5
  • Platform: Apple M3 Pro

Other details

Based on local testing, the likely root cause appears to be as follows:

After downloading myapp.app.zip, the extractArtifact method is executed in ArtifactUnpacker due to the zip file format.

case .zip:
let extractedURL = try extractArtifact(at: artifactURL)

The extractArtifact method unzip myapp.app.zip into a myapp.app directory (without the .zip extension), resulting in a nested structure like $DOWNLOADED_DIRECTORY/myapp.app/myapp.app. The method returns $DOWNLOADED_DIRECTORY/myapp.app as a destination.

private func extractArtifact(at url: URL) throws -> URL {
let destination = url.deletingLastPathComponent().appending(path: url.fileName)
try FileManager.default.unzipItem(at: url, to: destination)
try? FileManager.default.removeItem(at: url)
return destination
}

The unpack method is then called again with extractedURL as an argument.

let extractedURL = try extractArtifact(at: artifactURL)
return try unpack(artifactURL: extractedURL)

Since artifactURL is $DOWNLOADED_DIRECTORY/myapp.app, the file format is interpreted as applicationBundle, and AppleApplication(bundleURL:) is returned. However, the correct bundleURL should be $DOWNLOADED_DIRECTORY/myapp.app/myapp.app.
As a result, the incorrect download path prevents the bundle from being installed on the iOS simulator.

case .applicationBundle:
return AppleApplication(bundleURL: artifactURL)

@lfroms
Copy link
Member

lfroms commented Nov 18, 2024

The unzip mechanism is currently working as expected, but Tophat should definitely handle this better to avoid the issue you described, so I'm open to ideas.

The reason you're observing this behaviour is likely because you're zipping the .app (which is actually a directory) rather than zipping the contents of the .app. When exporting an application from Xcode, Xcode will produce a zip file containing the contents. As a result, extracting said zip file will place the .app as a sibling to the originating .zip, so Tophat currently follows this assumption so that it is compatible with Xcode artifacts out of the box.

Tophat should probably be smart enough to detect a .app in a nested directory and not make assumptions about the name of the zip file.

@lfroms
Copy link
Member

lfroms commented Nov 18, 2024

This should be pretty easy to validate as well. Try compressing this way, from inside the .app:

cd MyApp.app
zip -r ../MyApp.app.zip .

@natmark
Copy link
Author

natmark commented Nov 20, 2024

Thank you for your response.

By compressing the contents of the .app directory using zip -r ../MyApp.app.zip . as you suggested, I was indeed able to use it with Tophat.

I have been archiving for the iOS Simulator using xcodebuild and preparing the compressed .app.zip file by compressing the .app bundle within the .xcarchive. For this reason, I was not aware of the behavior you mentioned, "When exporting an application from Xcode, Xcode will produce a zip file containing the contents."

[IMO] It might be a good idea to check whether the .app itself was compressed or its contents were compressed by verifying the existence of the Info.plist file inside the .app directory after unzipping.

@lfroms
Copy link
Member

lfroms commented Nov 20, 2024

[IMO] It might be a good idea to check whether the .app itself was compressed or its contents were compressed by verifying the existence of the Info.plist file inside the .app directory after unzipping.

Yes, definitely agree with that. Not sure what the best approach is; checking Info.plist existence is certainly one of them. If you have an idea, contributions are certainly welcome!

@lfroms lfroms changed the title Cannot install zip archived application bundle on iOS simulator Unable to handle application bundles zipped with a parent directory Dec 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants