Bundle Programming Guide

Introduction

Bundle是OS X和iOS中用来结构性封装代码和相关数据文件的技术。

在Xcode中新建project的时候会自动帮你创建好相应的项目结构:

bundle-sample1

Organization of This Document

  • About Bundles 介绍Bundle/Package的具体概念及其在系统中的作用。
  • Bundle Structures 一般bundle的结构和内容。
  • Accessing a Bundle‘s Contents 访问Bundle内的资源。
  • Document Packages Document Package的概念。

About Bundles

Bundle and Packages

  • Package 是泛指在Finder中显示为一个文件的隐性文件目录(file directory)。
  • Bundle 是具有标准化分层结构(具体标准根据项目类型决定)而且包含代码和相关数据文件的文件目录,在Finder中也是显示为一个文件。

Package让OS X更加容易使用的关键在于,在用户面前它把app封装称为一个文件,让用户可以很方便的安装和卸载,并且可以防止用户不小心删除app内重要的文件。

Finder -> 应用程序 里面对app点右键,选择“显示包内容”可以进入app目录并修改里面的文件。

Bundle和Package并不是两个木有交集的概念,很多Bundle也算是Package(application和loadable bundles也是package)。

How the System Identifies Bundles and Packages

  • 文件后缀为 .app.bundle.framework.plugin.kext等。
  • 文件后缀被其他app声明为package类型。
  • 包含自己的package bitset。

About Bundle Display Names

默认情况下bundle的displayname和name一样(如果不用localized name的话),但是finder显示的是displayname,用户可以修改的也是displayname。

The Advances of Bundles

  • 可以被当成是文件目录打开。
  • 简化语言本地化操作。
  • 适应多种文件系统。
  • 用户可以方便地在Finder中通过拖拽实现app的安装卸载。
  • 防止被用户随意更改内容。
  • 支持多种架构。
  • 支持大部分语言。
  • 可以直接在server里面运行。

Types of Bundles

  • Application
  • Frameworks
  • Plug-Ins

Creating a Bundle

直接用Xcode创建平project就可以(个别target不会主动创建Bundle)。

也可以自己手动创建。

Programming Support for Accessing Bundles

Cocoa 和 Core Foundation框架均支持(NSBundle和CFBundle)。

Guidelines for Using Bundles

Bundle是OS X和iOS下官方建议的app文件系统组织机制。

  • Bundle内的Info.plist文件必须包含必要的关键字及对应内容。
  • 把app运行时必要文件include进来。
  • 如果app内需要加载C++代码,要做好文件标记。
  • 不能使用NSBundle来加载Code Fragment Manager(CFM)代码。
  • 使用NSBundle来加载包含java的代码。
  • NSBundle和CFBundle加载Objective-C的不同在于是否全局加载和何时做绑定(?)。

Bundle Structures

在不同平台下 OS X和iOS 不同。

UNIX shell scripts 、 command-line tools static/dynamic shared libraries不适用bundle结构。

Application Bundles

What Files Go Into an Application Bundle?

File Description
Info.plist (必要)“ information property list ”包含app的一些配置信息,系统依靠这些信息来辨认该app。
Executable (必要)至少包含一个代码文件提供程序入口。
Resource files iOS平台下一般包含images, icons, default screen, sounds, nib files, strings files, configuration files, and data files (among others).
Other support files iOS下不能把使用custom frameworks或者plug-ins,OS X可以。

Anatomy of an iOS Application Bundle

一个典型的iOS app的bundle目录栗子:

MyApp.app
     MyApp
     MyAppIcon.png
     MySearchIcon.png
     Info.plist
     Default.png
     MainWindow.nib
     Settings.bundle
     MySettingsIcon.png
     iTunesArtwork
     en.lproj
        MyImage.png
     fr.lproj
        MyImage.png

说明:

File Description
MyApp (必要)可执行代码文件放在里面。文件夹名字和app名字一致。
Application icons
(MyAppIcon.png, MySearchIcon.png, MySettingsIcon.png)
(建议有)在app内部使用的icon。
Info.plist (必要)包含app重要信息,如bundle ID, version number, and display name等。
Launch images
(Default.png)
(建议要)app打开的时候展示的全屏图片。
MainWindow.nib (建议)默认的用户界面模板文件。也可以自己修改为其他nib,但是需要在Info.plist中设置为默认启动项。
Settings.bundle setting bundle是一种特殊的plug-in,包含了一些app偏好设置,用来让用户可以在Setting中设置。
Custom resource files 非localized型资源文件直接放在bundle的根目录,localized型文件放在对应的文件夹(.lproj)。这些文件包含但不限于:nib files, images, sound files, configuration files, strings files。

The Information Property List File

每一个app都必须包含一个information property list(Info.plist)文件,描述app的一些关键信息。Xcode会在创建app 项目的时候帮你创建。这是一个包含Key-Value信息的XML文件。

包含的必要信息:

Key Value
CFBundleDisplayName
(Bundle display name)
用户看到的app名字,应该做好localized。
CFBundleIdentifier
(Bundle identifier)
在系统中标识app的关键字,栗子: com.Ajax.Hello 。
CFBundleVersion
(Bundle version)
app版本信息。
CFBundleIconFiles (建议有)array,包含app使用的中各种各样的icons
LSRequiresIPhoneOS
(Application requires iOS environment)
默认是true,建议不要管他。
UIRequiredDeviceCapabilities 和设备相关的app运行要求。

其他:

Key Value
NSMainNibFile
(Main nib file base name)
app启动时载入的nib文件。
UIStatusBarStyle 默认是UIStatusBarStyleDefault, 详细见UIApplication.h。
UIStatusBarHidden 是否隐藏状态栏,默认是false。
UIInterfaceOrientaion app启动时的显示方向,默认是UIInterfaceOrientationPortrait。
UIPrerenderedIcon icon是否增加高光和斜角效果,默认是false。
UIRequiesPersistenWiFi 声明屏幕关闭后是否断开wifi,实际上并没有什么用。系统还是会自动断开wifi。默认是false。
UILaunchImageFile app启动时的展示图,默认文件名是Default。

Application Icon and Launch Images

app Icon和Iaunch Image 都要放在bundle根目录。建议将icon写入到info.plist的CFBundleIconFiles里。

Launch Image也可以Localized。

Resources in an iOS Application

自己创建的resource file可以使用子文件夹安放。其他系统指定的非localized都要放在bundle根目录。

栗子:

MyApp.app/
    Info.plist
     MyApp
     Default.png
     Icon.png
     Hand.png
     MainWindow.nib
     MyAppViewController.nib
     WaterSounds/
         Water1.aiff
        Water2.aiff
     en.lproj/
        CustomView.nib
        bird.png
        Bye.txt
        Localizable.strings
     jp.lproj/
        CustomView.nib
        bird.png
        Bye.txt
        Localizable.strings

Creating an Application Bundle

最简单的方法是使用Xcode创建。

Framework Bundles

Loadable Bundles

Localized Resource in Bundles

参考上面的栗子,命名规则是:

language_region.lproj

language标准来源于ISO 639 conventions
region标准来源于ISO 3166 conventions(可选)

栗子:

en_GB.lproj
en_AU.lproj
en_US.lproj

//省略region:
en.lproj

//这样也可以,但是不建议
English.lproj
German.lproj
Japanese.lproj

一个混合地区和语言的栗子:

Resources/
   MyApp.icns
   en_GB.lproj/
      MyApp.nib
      bird.tiff
      Localizable.strings
   en_US.lproj/
        MyApp.nib
      Localizable.strings
   en.lproj/
        MyApp.nib
        bird.tiff
        Bye.txt
        house.jpg
        InfoPlist.strings
        Localizable.strings
        CitySounds/
           city1.aiff
           city2.aiff

关于语言本地化使用方法见《Internationalization and Localization Guide》。

Accessing a Bundle's Contents

Locating and Opening Bundles

Getting the Main Bundle

Cocoa

NSBundle* mainBundle;

// Get the main bundle for the app.
mainBundle = [NSBundle mainBundle];

Core Founadation

CFBundleRef mainBundle;

// Get the main bundle for the app
mainBundle = CFBundleGetMainBundle();

两种例外:

  • If a program is not bundled, attempting to get the main bundle might return a NULL value. The bundle code may try to create a main bundle to represent your program’s contents, but doing so is not possible in all cases.
  • If the agent that launched the program did not specify the full path to the program's executable in the argv parameters, the main bundle value might be NULL. Bundles rely on either the path to the executable being in argv[0] or the presence of the executable's path in the PATH environment variable. If neither of these is present, the bundle routines might not be able to find the main bundle directory. Programs launched by xinetd often experience this problem when xinetd changes the current directory to /.

Getting Bundles by Path

Cocoa

NSBundle* myBundle;

// Obtain a reference to a loadable bundle.
myBundle = [NSBundle bundleWithPath:@"/Library/MyBundle.bundle"];

Core Foundation

CFURLRef bundleURL;
CFBundleRef myBundle;
// Make a CFURLRef from the CFString representation of the
// bundle’s path.
bundleURL = CFURLCreateWithFileSystemPath(
                kCFAllocatorDefault,
                CFSTR("/Library/MyBundle.bundle"),
                kCFURLPOSIXPathStyle,
                true );
// Make a bundle instance using the URLRef.
myBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
// You can release the URL now.
CFRelease( bundleURL );
// Use the bundle...
// Release the bundle when done.
CFRelease( myBundle );

Getting Bundles in Known Directories

这个在iOS应该用不到。

CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef plugInsURL;
CFArrayRef bundleArray;
// Get the URL to the application’s PlugIns directory.
plugInsURL = CFBundleCopyBuiltInPlugInsURL(mainBundle);
// Get the bundle objects for the application’s plug-ins.
bundleArray = CFBundleCreateBundlesFromDirectory( kCFAllocatorDefault,plugInsURL, NULL );
// Release the CF objects when done with them.
CFRelease( plugInsURL );
CFRelease( bundleArray );

Getting Bundles by Identifier

Cocoa

NSBundle* myBundle = [NSBundle bundleWithIdentifier:@"com.apple.myPlugin"];

Core Foundation

CFBundleRef requestedBundle;


 // Look for a bundle using its identifier
 requestedBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Finder.MyGetInfoPlugIn") );

Searching for Related Bundles

使用NSBundle的allBundles,allFrameworks获取。

Getting References to Bundle Resources

The Bundle Search Pattern

NSBundle和CFBundleRef检索顺序如下:

  1. Global (nonlocalized) resoureces //全局
  2. Region-specific localized resources (based on the user’s region preferences)//地区
  3. Language-specific localized resources (based on the user’s language preferences)//语言
  4. Development language resources (as specified by the CFBundleDevelopmentRegion in the bundle’s Info.plist file.)//dev配置

即使在大小写不敏感的文件系统,bundle也是大小写敏感的。

Device-Specific Resources in iOS

<basename> <device> .<filename_extension>

可选device:

  • ~ipad - The resource should be loaded on iPad devices only.
  • ~iphone - The resource should be loaded on iPhone or iPod touch devices only.

如果Bundle根目录有下面两个文件:

  • MyImage~ipad.png
  • MyImage~iphone.png

使用

UIImage* anImage = [UIImage imageNamed:@"MyImage.png"];

即可完成根据设备的自动选择。

Getting the Path to a Resource

使用文件名和类型获取Path。

Using Cocoa to Find Resources

可用函数:

  • pathForResource:ofType:
  • pathForResource:ofType:inDirectory:
  • pathForResource:ofType:inDirectory:forLocalization:
  • pathsForResourcesOfType:inDirectory:
  • pathsForResourcesOfType:inDirectory:forLocalization:

栗子:

NSBundle* myBundle = [NSBundle mainBundle];
NSString* myImage = [myBundle pathForResource:@"Seagull" ofType:@"jpg"];

NSBundle* myBundle = [NSBundle mainBundle];
NSArray* myImages = [myBundle pathsForResourcesOfType:@"jpg"
                              inDirectory:nil];

Using Core Foundation to Find Resources

可用函数:

  • CFBundleCopyResourceURL
  • CFBundleCopyResourceURLInDirectory
  • CFBundleCopyResourceURLsOfType
  • CFBundleCopyResourceURLsOfTypeInDirectory
  • CFBundleCopyResourceURLsOfTypeForLocalization

栗子:

CFURLRef    seagullURL;
// Look for a resource in the main bundle by name and type.
seagullURL = CFBundleCopyResourceURL( mainBundle,
                CFSTR("Seagull"),
                CFSTR("jpg"),
                NULL );

CFArrayRef  birdURLs;
// Find all of the JPEG images in a given directory.
birdURLs = CFBundleCopyResourceURLsOfType( mainBundle,
                CFSTR("jpg"),
                CFSTR("BirdImages") );

文件类型声明为NULL可以搜索没有拓展名的文件。

Opening and Using Resource Files

详见《Resource Programming Guide》。

Finding Other Files in a Bundle

To get the path to the top-level bundle directory using Cocoa, you use the bundlePath method of the corresponding NSBundle object. You can also use the builtInPlugInsPath, resourcePath, sharedFrameworksPath, and sharedSupportPath methods to obtain the paths for key subdirectories of the bundle. These methods return path information using an NSString object, which you can pass directly to most other NSBundle methods or convert to an NSURL object as needed.

Getting the Bundle's Info.plist Data

使用NSBundle的objectForInfoDictionaryKey:infoDictionary即可。详见NSBundle Class Reference。

Core Foundation可以使用CFBundleGetValueForInfoDictionaryKeyCFBundleGetInfoDictionary获取。比起Cocoa的NSBundle,这两个函数可以获取localizedvalues。

栗子:

// This is the ‘vers’ resource style value for 1.0.0
#define kMyBundleVersion1 0x01008000
UInt32  bundleVersion;
// Look for the bundle’s version number.
bundleVersion = CFBundleGetVersionNumber( mainBundle );
// Check the bundle version for compatibility with the app.
if (bundleVersion < kMyBundleVersion1)
return (kErrorFatalBundleTooOld);
CFDictionaryRef bundleInfoDict;
CFStringRef     myPropertyString;
// Get an instance of the non-localized keys.
bundleInfoDict = CFBundleGetInfoDictionary( myBundle );
// If we succeeded, look for our property.
if ( bundleInfoDict != NULL ) {
    myPropertyString = CFDictionaryGetValue( bundleInfoDict,
                CFSTR("MyPropertyKey") );
}

Loading and Unloading Executable Code

木有看

Document Packages

木有看

Glossary

  • bundle AdirectorythatcontainsanGlossary(page 50) and whose contents are organized in one of several ways recognized by the system.
  • display name Auser-visiblestringdisplayedinplace of an item’s actual name. Display names allow the user to customize the names of key items (like applications) without breaking parts of the system that rely on the original name.
  • framework Abundlestructurecontaininga dynamic shared library and the header files and other resources to support that library.
  • information property list Aspecifictypeof property list that contains configuration information for a bundle. An information property list file must always have the name Info.plist. For more information, see Runtime Configuration Guidelines .
  • loadable bundle Abundlewhoseexecutableis designed to be loaded into memory dynamically by an application. Loadable bundles are also sometimes referred to as plug-ins.
  • package AdirectorythattheFinderpresentstothe user as if it were a single file.
  • target AnXcodeblueprintforcreatingaproduct. A target defines rules for compiling source files, copy resource files, and performing any other steps needed to build the resulting product.
  • versioned bundle Abundlethatsupportsthe inclusion of multiple versions of an executable and resources. Frameworks are the only type of bundle that support versions.

标签:ios, object-c