In Xcode 3, applications were archived in .apparchive folders.
In Xcode 4, applications are now archived in an .xcarchive bundle.
Is there a way开发者_高级运维 to convert .apparchive folders in .xcarchive bundles or to open .apparchive folders with Xcode 4?
Dave Dunkin's script worked great, but I missed the icon and version in some cases. Below a slightly adjusted version of the script. You need to install MacRuby, available here: http://www.macruby.org/downloads.html.
#!/System/Library/PrivateFrameworks/MacRuby.framework/Versions/A/usr/bin/macruby
framework 'Cocoa'
require 'date'
require 'fileutils'
Dir.glob(Dir.home() + '/Library/Application Support/Developer/Shared/Archived Applications/*.apparchive').each { |apparchivePath|
print "Found archive at #{apparchivePath}... "
archiveInfo = NSDictionary.dictionaryWithContentsOfURL(NSURL.fileURLWithPath(apparchivePath + '/ArchiveInfo.plist'))
name = archiveInfo['XCUserProvidedName'] || archiveInfo['XCApplicationName']
appFilename = archiveInfo['XCApplicationFilename']
appPath = 'Applications/' + appFilename
archiveDate = archiveInfo['XCArchivedDate']
xcarchivePath = Dir.home() + '/Library/Developer/Xcode/Archives/' + archiveDate.strftime('%Y-%m-%d') + '/' + name + ' ' + archiveDate.strftime('%m-%d-%y %I.%M %p') + '.xcarchive'
appVersion = archiveInfo['CFBundleVersion']
iconPaths = archiveInfo['XCInfoPlist']['CFBundleIconFiles']
if not iconPaths
iconPaths = appPath + '/' + archiveInfo['XCInfoPlist']['CFBundleIconFile']
else
iconPaths = archiveInfo['XCInfoPlist']['CFBundleIconFiles'].collect { |f| appPath + '/' + f }
end
if File.directory?(xcarchivePath)
puts 'skipping'
else
puts 'importing'
FileUtils.mkdir_p(xcarchivePath)
xcarchiveInfo = {
'ApplicationProperties' => {
'ApplicationPath' => appPath,
'CFBundleIdentifier' => archiveInfo['CFBundleIdentifier'],
'CFBundleShortVersionString' => appVersion,
'IconPaths' => iconPaths
},
'ArchiveVersion' => 1,
'CreationDate' => archiveDate,
'Name' => name,
'SchemeName' => archiveInfo['XCApplicationName']
}
if archiveInfo.has_key?('XCUserProvidedComment')
xcarchiveInfo['Comment'] = archiveInfo['XCUserProvidedComment']
end
xcarchiveInfo.writeToURL(NSURL.fileURLWithPath(xcarchivePath + '/Info.plist'), atomically:false)
FileUtils.mkdir_p(xcarchivePath + '/Products/Applications')
FileUtils.cp_r(apparchivePath + '/' + appFilename, xcarchivePath + '/Products/Applications')
FileUtils.mkdir_p(xcarchivePath + '/dSYMs')
FileUtils.cp_r(apparchivePath + '/' + appFilename + '.dSYM', xcarchivePath + '/dSYMs')
end
}
Here's a MacRuby script I wrote to do this for me.
#!/usr/local/bin/macruby
framework 'Cocoa'
require 'date'
require 'fileutils'
Dir.glob(Dir.home() + '/Library/Application Support/Developer/Shared/Archived Applications/*.apparchive').each { |apparchivePath|
print "Found archive at #{apparchivePath}... "
archiveInfo = NSDictionary.dictionaryWithContentsOfURL(NSURL.fileURLWithPath(apparchivePath + '/ArchiveInfo.plist'))
name = archiveInfo['XCUserProvidedName'] || archiveInfo['XCApplicationName']
appFilename = archiveInfo['XCApplicationFilename']
appPath = 'Applications/' + appFilename
archiveDate = archiveInfo['XCArchivedDate']
xcarchivePath = Dir.home() + '/Library/Developer/Xcode/Archives/' + archiveDate.strftime('%Y-%m-%d') + '/' + name + ' ' + archiveDate.strftime('%m-%d-%y %I.%M %p') + '.xcarchive'
if File.directory?(xcarchivePath)
puts 'skipping'
else
puts 'importing'
FileUtils.mkdir_p(xcarchivePath)
xcarchiveInfo = {
'ApplicationProperties' => {
'ApplicationPath' => appPath,
'CFBundleIdentifier' => archiveInfo['CFBundleIdentifier'],
'IconPaths' => archiveInfo['XCInfoPlist']['CFBundleIconFiles'].collect { |f| appPath + '/' + f }
},
'ArchiveVersion' => 1,
'CreationDate' => archiveDate,
'Name' => name,
'SchemeName' => archiveInfo['XCApplicationName']
}
if archiveInfo.has_key?('XCUserProvidedComment')
xcarchiveInfo['Comment'] = archiveInfo['XCUserProvidedComment']
end
xcarchiveInfo.writeToURL(NSURL.fileURLWithPath(xcarchivePath + '/Info.plist'), atomically:false)
FileUtils.mkdir_p(xcarchivePath + '/Products/Applications')
FileUtils.cp_r(apparchivePath + '/' + appFilename, xcarchivePath + '/Products/Applications')
FileUtils.mkdir_p(xcarchivePath + '/dSYMs')
FileUtils.cp_r(apparchivePath + '/' + appFilename + '.dSYM', xcarchivePath + '/dSYMs')
end
}
I just did one by hand, so it's definitely possible, but tedious for more than one or two. With a bit of time, someone could write a script to do this.
.xcarchive
bundles are just directories, like .apparchive
bundles before them. The newer format moved some things around and simplified the top level Info.plist
.
Xcode 3 stores the archives in ~/Library/Application Support/Developer/Shared/Archived Applications
. Individual archive bundles are named as a GUID. Inside each is the ArchiveInfo.plist
, the actual .app
bundle and the .dSYM
bundle.
Xcode 4 stores the archives in ~/Library/Developer/Xcode/Archives
, separated into folders named after the date the archive is created. Within each date folder is the .xcarchive
bundle, using a readable name instead of a GUID. Within that is the Info.plist
, a Products
folder where the .app
lives, and a dSYMs
folder to hold the .dSYM
bundles.
A quick-and-dirty way to copy a .apparchive
to a .xcarchive
:
- Create a new folder with the date when the archive was created.
- Copy the contents of the
.apparchive
into a new folder ending with.xcarchive
inside that new folder. cd
into that new.xcarchive
folder. Everything is relative to that from this point forward.- Create
Products
anddSYMs
folders. - Move your
.app
bundle intoProducts
. - Move your
.dSYM
bundle intodSYMs
. - Remove the old
ArchiveInfo.plist
file. - Create a new
Info.plist
that looks like this, substituting as appropriate.
(ending the list so StackOverflow formats the XML properly...)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ApplicationProperties</key>
<dict>
<key>ApplicationPath</key>
<string>AppBundleName.app</string>
<key>CFBundleIdentifier</key>
<string>com.example.app-id</string>
<key>IconPaths</key>
<array>
<string>AppBundleName.app/Icon.png</string>
<string>AppBundleName.app/Icon-Small.png</string>
</array>
</dict>
<key>ArchiveVersion</key>
<real>1</real>
<key>CreationDate</key>
<date>2010-12-15T15:10:34Z</date> <!-- this is a GMT time stamp -->
<key>Name</key>
<string>AppName</string>
<key>SchemeName</key>
<string>AppName</string>
</dict>
</plist>
精彩评论