提高表视图的性能
- (void)loadAnimals { _animalList = [NSMutableArray arrayWithCapacity:rAnimalCount]; for (NSInteger i = 0; i < rAnimalCount; i++) { Animal *animal = [[Animal alloc] init]; NSString *name = [NSString stringWithFormat:@"Animal-%03d", i+1]; NSString *detail = [NSString stringWithFormat:@"dog or cat?"]; NSInteger seed = arc4random()%8 + 1; NSString *imageName = [NSString stringWithFormat:@"head%02d", seed+1]; animal.name = name; animal.detail = detail; animal.imageName = imageName; [_animalList addObject:animal]; } }
重点在于绘制,我首先创建了一个继承自UITableViewCell的父类一会让我们的单元格继承它,父类中有一个UIView类型的contentView成员,所有的绘制将在这个成员上进行。
@interface HRCellView : UIView @end @implementation HRCellView - (void)drawRect:(CGRect)rect { [(HRCell *)[self superview] drawContentView:rect]; } @end @implementation HRCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { contentView = [[HRCellView alloc] init]; contentView.opaque = YES; //不透明,提升渲染性能 [self addSubview:contentView]; } return self; } - (void)setFrame:(CGRect)frame { [super setFrame:frame]; CGRect b = [self bounds]; b.size.height -= 1; // 给分割线留出位置 contentView.frame = b; } - (void)setNeedsDisplay { [super setNeedsDisplay]; [contentView setNeedsDisplay]; } - (void)drawContentView:(CGRect)rect { //子类实现 } @end
static UIFont *NameFont; static UIFont *DetailFont; @implementation HRCustomCell + (void)initialize { NameFont = [UIFont fontWithName:@"American Typewriter" size:rNameFontSize]; DetailFont = [UIFont fontWithName:@"American Typewriter" size:rDetailFontSize]; }
将数据绑定到这个单元格中
- (void)bindAnimal:(Animal *)animal { if (_nameText != animal.name) { _nameText = animal.name; } if (_detailText != animal.detail) { _detailText = animal.detail; } if (_imageName != animal.imageName) { _imageName = animal.imageName; } [self setNeedsDisplay]; }
- (void)drawContentView:(CGRect)rect { static UIColor *nameColor; nameColor = [UIColor blackColor]; static UIColor *detailColor; detailColor = [UIColor darkGrayColor]; CGContextRef context = UIGraphicsGetCurrentContext(); CGRect cellRect = self.frame; if (self.highlighted || self.selected) //选择或高亮时对应的颜色 { CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor); CGContextFillRect(context, CGRectMake(0, 0, cellRect.size.width, cellRect.size.height)); } else { CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); CGContextFillRect(context, CGRectMake(0, 0, cellRect.size.width, cellRect.size.height)); } UIImage *image = [UIImage imageNamed:_imageName]; [image drawInRect:CGRectMake(5, 5, 50, 50)]; [nameColor set]; [_nameText drawAtPoint:CGPointMake(65, 10) forWidth:200 withFont:NameFont fontSize:rNameFontSize lineBreakMode:NSLineBreakByWordWrapping baselineAdjustment:UIBaselineAdjustmentAlignBaselines]; [detailColor set]; [_detailText drawAtPoint:CGPointMake(180, 40) forWidth:120 withFont:DetailFont fontSize:rDetailFontSize lineBreakMode:NSLineBreakByWordWrapping baselineAdjustment:UIBaselineAdjustmentAlignBaselines]; }
虽然方法很长,但是只要会简单的quartz绘图这些都是最基础的方法。
翻译自 Features Reference
下表列出了软/硬件Feature和权限的参考信息,它们被用于GooglePlay。
硬件feature下面列出了被大多数当前发布的平台所支持的硬件功能描述。为了标明应用程序所使用或需要的某个硬件Feature,都要在一个独立的<uses-feature>元素的android:name属性中声明。
Feature类型
Feature描述符
描述
注释
Audio
android.hardware.audio.low_latency
应用程序使用设备上的低延迟的音频通道,并且对于输入或输出的延迟或之后是敏感的。
Bluetooth
android.hardware.bluetooth
应用程序要使用设备中的蓝牙射频Feature。
Camera
android.hardware.camera
应用程序要使用设备的摄像头,如果设备支持多个摄像头,那么应用程序会使用屏幕背面的那个。
android.hardware.camera.autofocus
子Feature。应用程序要使用设备摄像头的自动对焦能力。
这些子Feature隐式的声明了android.hardware.camera的父功能,除非声明了android:required="false"。
android.hardware.camera.flash
子Feature。应用程序要使用设备摄像头的闪光灯能力。
android.hardware.camera.front
子Feature。应用程序要使用设备上的前置摄像头。
android.hardware.camera.any
应用程序至少使用了任何方向上的摄像头。如果后摄像头不是必须的可以用android.hardware.camera。.
Location
android.hardware.location
应用程序会使用设备上的多种功能来获取位置,如GPS定位、网络定位、或小区定位。
android.hardware.location.network
子Feature,应用程序要从设备上所支持的基于网络的定位系统来获取大概的位置坐标。
这些子Feature的声明,就隐式的声明了android.hardware.location父Feature,除非其声明了android:required="false"。
android.hardware.location.gps
子Feature,应用程序使用了从设备上的全球定位系统接收器中获取精确的坐标。
Microphone
android.hardware.microphone
应用程序要使用设备上的麦克风。
NFC
android.hardware.nfc
应用程序要使用设备中的NFC近距离无线通信功能。
Sensors
android.hardware.sensor.accelerometer
应用程序要使用设备上的加速度传感器的运动读数。
android.hardware.sensor.barometer
应用程序要使用设备的压力传感器。
android.hardware.sensor.compass
应用程序要使用设备上的磁极(罗盘)来读取方向读数。
android.hardware.sensor.gyroscope
应用程序要使用设备上的陀螺仪。
android.hardware.sensor.light
应用程序要使用设备的亮度传感器。
android.hardware.sensor.proximity
应用程序要使用设备的接近proximity传感器。
Screen
android.hardware.screen.landscape
应用程序需要横向屏幕
例如:如果应用程序需要纵向屏幕,就应该声明<uses-featureandroid:name="android.hardware.screen.portrait"/>,以便只有支持纵向的设备能够安装该应用程序。如果应用程序两个方向都支持,那么就不需要做任何声明。
默认情况下,这两个方向都被假定为不需要,因此应用程序可以安装在支持一个方向或两个方向都支持的设备上。然而,一旦应用程序使用android:screenOrientation属性,设定要运行在一个特定的设备上,就声明了应用程序需要screen方向的Feature。例如,如果用android:screenOrientation属性声明了"landscape","reverseLandscape", 或"sensorLandscape"值,那么应用程序只对支持横向屏幕的设备有效。最好的实践是,依然使用<uses-feature>元素声明一个方向的Feature请求。如果使用android:screenOrientation,属性给Activity声明了一个方向,但实际却不需要该Feature请求,那么就可以通过<uses-feature>元素并包含android:required="false"来禁止该Feature需求。
为了向后兼容,任何平台版本只支持APILevel 12或更低的的设备,都被假定为同时支持横向和纵向屏幕。
android.hardware.screen.portrait
应用程序需要纵向屏幕
Telephony
android.hardware.telephony
应用程序要使用设备设备上的电话Feature,如带有数据通信服务的无线电话。
android.hardware.telephony.cdma
子Feature,应用程序要使用设备上的CDMA无线电话功能
这些子Feature隐式的声明了android.hardware.telephony父Feature,除非该功能需求声明了android:required="false"属性。
android.hardware.telephony.gsm
子Feature,应用程序要使用设备上的GSM无线电话功能
Television
android.hardware.type.television
The application is designed for a television user experience.
This feature defines "television" to be a typicalliving room television experience: displayed on a big screen,where the user is sitting far away and the dominant form of inputis something like a d-pad, and generally not through touch or amouse/pointer-device.
Touchscreen
android.hardware.faketouch
应用程序要使用基本的触屏事件,如“clickdown”、“clickup”和“drag”
当应用程序声明了这个功能需求时,则表明该应用程序只能跟提供了模拟触屏(faketouch 接口)操作的设备兼容。提供faketouch接口的设备会给用户提供一种模拟触屏能力的输入系统。例如,驱动屏幕光标提供faketouch接口的鼠标或远程控制。如果应用程序需要基本的点和click交互(换句话说,只有一个方向板(d-pad),应用程序是不会工作的),就应该声明这个功能,因为这是触屏交互的最低级别,这样应用程序也会跟提供更复杂的触屏交互的设备兼容。
注意:默认情况下,因为应用程序需要android.hardware.touchscreenFeature,所以如果想要应用程序对提供了faketouch接口的设备有效,那么就必须通过声明<uses-featureandroid:name="android.hardware.touchscreen"android:required="false"/>,来明确的声明触屏不是必须的。
android.hardware.faketouch.multitouch.distinct
应用程序要在faketouch(假触屏)表面上执行区分两点以上触摸的轨迹的操作,这是faketouce功能的一个超集。
当应用程序声明了这个需求时,表明该应用程序只跟支持区分两点以上的模拟触屏事件的设备兼容。
跟通过android.hardware.touchscreen.multitouch.distinct定义的多点触控不同,支持在faketouch表面进行两点以上触控输入的设备,它不支持所有的双指手势,因为当前输入会被转换成平面上的光标移动。也就是说,在这样设备上的单指手势会移动光标,双指碰擦会导致单指的触屏事件;其他的双指手势会导致相应的双指触屏事件。例如:提供了移动光标的和多指触控的轨迹板,就是一种支持在faketouch表面执行区分多点触控的设备。
android.hardware.faketouch.multitouch.jazzhand
应用程序要在faketouch(假触屏)表面上执行区分五点以上触摸的轨迹的操作,这是faketouce功能的一个超集。
当应用程序声明这个功能需求时,表明该应用程序只会跟支持区分五点以上轨迹的模拟触屏设备兼容。
跟通过android.hardware.touchscreen.multitouch.jazzhand定义的多点触控不同,该功能定义的输入设备表面不会支持所有的五指手势,因为该输入会转换成屏幕上的光标移动。也就是说,单指手势会移动设备上的光标,多指触碰手势会导致一个单指触碰事件;其他的多指手势会导致相应的多指触碰事件。例如:提供了移动光标的和多指触控的轨迹板,就是一种支持在faketouch表面执行区分多点触控的设备。
android.hardware.touchscreen
应用程序要使用比基本的触屏事件还要多的手势交互功能,如,抛物手势。该功能是基本faketouch功能的一个超集。
默认情况下,应用程序需要这个功能。因此,默认情况下,应用程序对只提供模拟触摸屏(faketouch)的设备是无效的。如果想要应用程序对提供模拟触摸屏的设备有效,就必须明确的声明触摸屏不是必须的,声明方式如下:<uses-featurename=”android:hardware.touchscreen” android:required=”false”/>。即使应用程序不需要使用一个实际的触摸屏。
如果应用程序需要一个触摸屏(为了执行一些触碰手势),那么不需要做任何该功能的定义,因为默认这个功能是必须的。但是,最好还是明确的声明应用程序所要使用的全部功能,因此如果应用程序要使用该功能,依然还应该声明它。
如果需要更复杂的触摸交互,如多指手势,就应该声明下面的高级触屏功能。
android.hardware.touchscreen.multitouch
应用程序要使用多点触屏上的基本双点触摸功能,如掐捏手势,但不需要独立的轨迹跟踪。该功能是touchscreenFeature的一个超集。
声明该Feature,隐式的声明了android.hardware.touchscreen父Feature,除非该功能声明了android:required="false"属性。
android.hardware.touchscreen.multitouch.distinct
子Feature,应用程序要使用多点触屏设备的高级多点触摸功能,如两个以上完全独立的点的轨迹跟踪。它是multitouchFeature的子集。
声明该Feature,隐式的声明了android.hardware.touchscreen.multitouch父Feature,除非该功能声明了android:required="false"属性。
android.hardware.touchscreen.multitouch.jazzhand
该应用程序要使用多点触屏设备的多点触摸功能,如五个以上完全独立的点的轨迹跟踪。它是multitouchFeature的子集。
USB
android.hardware.usb.host
应用程序要使用USBHOST(主机)模式Feature(应用程序以主机的方式连接到USB设备上)
android.hardware.usb.accessory
应用程序要使用访问USB的Feature(应用程序以USB设备的方式连接到USBHOST/主机上)。
Wifi
android.hardware.wifi
应用程序使用设备上的802.11网络(wifi)Feature。
软件Feature列表
下表中列出了由当前大多数发布的Android平台所支持的软件Feature描述。对于应用程序要使用或需要的某一Feature,都要在应用程序的Manifest中的<uses-feature>元素中使用android:name属性来进行声明。
Feature
属性值
描述
注释
Live Wallpaper
android.software.live_wallpaper
应用程序使用或提供LiveWallpapers
SIP/VOIP
android.software.sip
应用程序使用SIP服务。
android.software.sip.voip
子Feature。应用程序要使用设备上的基于SIP的VOIP服务。
声明这个子Feature,隐式的声明了android.software.sip父Feature,除非声明该功能时也声明了android:required="false"。
隐式的Feature需求的权限
在上面列出的一些Feature常量中,要在相应的API发布之后,才对应用有效。例如,在Android2.2(APILevel 8)中添加了android.hardware.bluetooth功能常量,但是它所指向的蓝牙API是在Android2.0(APILevel5)中被添加的。正因为这样,某些应用能够在有能力通过<uses-feature>元素声明其所需的API功能之前,就能够使用这些API。
要防止无意间让某些功能对应用程序有效,GooglePlay会假定某些相关硬件的权限,来指定默认情况下所需要的底层硬件功能。例如,使用蓝牙功能的应用程序必须在<uses-permission>元素中申请BLUETOOTH权限,对于旧版应用程序,GooglePlay会假定权限的声明,意味着应用程序需要底层的android.hardware.bluetoothFeature,并且会基于该功能来过滤应用程序。
下表中列出的暗示功能需求的权限,等同于那些在<uses-feature>元素中声明的功能需求。要注意的是那些包含android:required属性的<uses-feature>声明,它的优先级要始终高于下表中隐式的的功能需求。
对于下表中的任何权限,都能够用带有android:required="false"属性的<uses-feature>元素来明确的禁止基于隐式功能的过滤。例如,要禁止基于CAMERA权限的任何过滤,可以在其清单文件中添加以下<uses-feature>元素的声明:
<uses-feature android:name="android.hardware.camera" android:required="false" />
分类
权限...
隐含的Feature需求
Bluetooth
BLUETOOTH
android.hardware.bluetooth
(详情参考Specialhandling for Bluetooth feature)
BLUETOOTH_ADMIN
android.hardware.bluetooth
Camera
CAMERA
android.hardware.camera and
android.hardware.camera.autofocus
Location
ACCESS_MOCK_LOCATION
android.hardware.location
ACCESS_LOCATION_EXTRA_COMMANDS
android.hardware.location
INSTALL_LOCATION_PROVIDER
android.hardware.location
ACCESS_COARSE_LOCATION
android.hardware.location.networkand
android.hardware.location
ACCESS_FINE_LOCATION
android.hardware.location.gps and
android.hardware.location
Microphone
RECORD_AUDIO
android.hardware.microphone
Telephony
CALL_PHONE
android.hardware.telephony
CALL_PRIVILEGED
android.hardware.telephony
MODIFY_PHONE_STATE
android.hardware.telephony
PROCESS_OUTGOING_CALLS
android.hardware.telephony
READ_SMS
android.hardware.telephony
RECEIVE_SMS
android.hardware.telephony
RECEIVE_MMS
android.hardware.telephony
RECEIVE_WAP_PUSH
android.hardware.telephony
SEND_SMS
android.hardware.telephony
WRITE_APN_SETTINGS
android.hardware.telephony
WRITE_SMS
android.hardware.telephony
Wifi
ACCESS_WIFI_STATE
android.hardware.wifi
CHANGE_WIFI_STATE
android.hardware.wifi
CHANGE_WIFI_MULTICAST_STATE
android.hardware.wifi
田海立@CSDN
翻译自Google Play and Feature-Based Filtering
GooglePlay会过滤出那些对用户可见的应用程序,因此用户只能看到和下载那些与他们的设备兼容的应用程序。过滤应用程序其中的一种方法就是通过Feature兼容性。
Google Play为判断应用程序与给定的用户设备是否兼容,比较:
应用程序需要的Feature– 应用程序在它自己的manifest中通过<uses-feature>申明所需要的Feature;
在设备上有效的硬/软件Feature-- 设备用只读的系统属性报告的它所支持的Feature。
为了确保Feature的准确比较,AndroidPackage Manager提供了一个共享的Feature常量集合,应用程序和设备都使用这些常量来声明各自所需要和支持的Feature。可用的Feature常量在本文下面的Feature参考表中被列出,它们定义在类文档PackageManager中。
当用户启动GooglePlay时,应用程序通过调用getSystemAvailableFeatures()方法,来查询包PackageManager中所列出的设备上可用的Featurelist。然后在建立用户会话的时候,软件商店(TheStore)应用程序会把这个Featurelist上传给GooglePlay。
每次把应用程序上传给GooglePlay的发布网站时,GooglePlay都会扫描应用程序的Manifest文件。它会查找Manifest中的<uses-feature>元素,并且在某些情况下,会把它们跟其他元素组合在一起来评估,如<uses-sdk>和<uses-permission>元素。在建立了应用程序所需的Feature集合之后,GooglePlay会把这个列表做为跟应用程序的.apk和版本相关联的内部元数据保存起来。
当用户使用GooglePlay应用程序查询或浏览应用商店里的应用程序时,服务就会把每个应用程序所需的Feature跟用户设备上可用的Feature进行比较。如果应用程序所需要的所有Feature在设备上都存在,那么GooglePlay就允许用户看到该应用程序,并潜在的可下载它。如果应用所需的任何一个Feature不被设备所支持,GooglePlay就过滤掉该应用程序,这样用户就看不到并且也不能够下载。
因为在<uses-feature>元素中声明的Feature直接影响到GooglePlay如何过滤应用程序,因此理解GooglePlay是如何评估应用程序的Manifest和建立需求Feature的集合是至关重要的,以下章节会详细说明。
基于明确声明Feature的过滤一个明确声明的Feature就是应用程序声明的一个<uses-feature>元素。Feature声明可以包含一个android:required=["true"| "false"]的属性(如果在APILeve5或以上的版本上编译),这个属性指定了应用程序是否绝对的需要该Feature,如果目标设备上不存在该Feature,该应用程序就不能正常的运行("true"的场合),或指定应用程序偏好该Feature,在Feature有效的时候就使用该它,而在该Feature无效时,应用程序也被设计成也是可以运行的("false"的场合)。
Google Play用以下方法来处理明确声明的Feature:
如果一个Feature被明确声明为必须的,那么GooglePlay就会把该Feature加入到该应用程序所需要的功能列表中。然后把应用程序从没有提供该应用所需Feature的设备中过滤掉。例如:
<uses-feature android:name="android.hardware.camera" android:required="true" />
如果一个Feature被明确声明为非必须的,GooglePlay就不会把这个的Feature添加到所需的Feature列表中。由于这个原因,明确声明的非必须的Feature,在GooglePlay过滤应用程序时就不会被考虑。即使设备不声明提供该Feature,GooglePlay依然会认为该应用程序与设备是兼容的,并允许显示给用户,除非使用了其他过滤规则。例如:
<uses-feature android:name="android.hardware.camera" android:required="false" />
如果一个Feature被明确声明,但没有设置android:required属性,那么GooglePlay就会假定该功能是必须的,并且要针对该功能进行过滤。(译者注:缺省是true)
通常,如果应用程序被设计成要运行在Android1.6或更早的版本上,那么在API中android:required属性是无效的,并且GooglePlay会假定<uses-feature>的申明都是必须的。
注意:通过明确声明一个Feature,并且包含android:required=”false”的属性,能够禁止GooglePlay针对该Feature的所有过滤。
基于隐式Feature的过滤一个隐式的Feature是为了让应用程序正确运行所需的功能,但是,这个Feature并不在申明在Manifest的<uses-feature>元素中。严格来说,每个应用程序都应该始终声明它所使用和需要的所有Feature,因此对于应用程序使用的Feature,却没有声明,应该被认为是一个错误。但是,出于对用户和开发者的保护,GooglePlay会查看每个应用程序的隐式Feature,并基于这些Feature来建立过滤器,就像是对明确声明的Feature所做的处理一样。
应用程序可能需要一个Feature,但却没有声明,这是因为:
应用程序是针对较旧的Android类库版本(Android1.5或更早)来编译的,当时<uses-feature>元素还是无效的;
开发者错误的假定所需要的Feature在所有的设备上都存在,而认为没有必要声明;
开发者不小心忽略的该Feature的声明;
开发者明确的声明了该Feature,但该声明是无效的。例如:<uses-feature>元素名的一个拼写错误或给android:name属性设定一个无法识别的字符串,这些都会导致Feature声明的无效。
To account for the cases above, Google Play attempts to discoveran application's implied feature requirements by examining otherelements declared in the manifest file, specifically,<uses-permission>elements.基于以上原因的考虑,GooglePlay会尝试通过检查Manifest文件中其他元素(特别是<uses-permission>元素)的声明来发现被应用隐式需要的Feature。
如果一个应用程序申请了硬件相关的权限,那么GooglePlay就会假定应用程序要使用底层的硬件Feature,并因此而需要那些Feature,即使可能没有相应的<uses-feature>声明。针对这样的权限申请,GooglePlay也会把底层的硬件Feature添加到它所保持的对应的应用程序的元数据中,并基于这些信息来建立相应的过滤器。
例如,如果应用程序申请了CAMERA权限,但却没有声明一个<uses-feature>元素要求android.hardware.cameraFeature,那么GooglePlay就会认为应用程序需要照相机,并且该应用程序不应该显示给没有提供照相机功能的那些用户设备。
如果不想要GooglePlay基于某个特殊的隐式Feature来过滤应用程序,就要禁止这种行为。通过在<uses-feature>元素中明确的声明Feature,并包含一个android:required="false"属性,可以达到禁止GooglePlay过滤应用程序的目的。例如:要禁止由CAMERA权限所派生出来的过滤,就要像下面这样声明Feature:
<uses-feature android:name="android.hardware.camera" android:required="false" />
理解用<uses-permission>元素声明的权限能够直接影响GooglePlay对应用程序的过滤是至关重要的。在下面的权限隐含的Feature需求章节中,列出了所有的隐含的Feature需求的权限集,并因此而引发的过滤处理。
对于蓝牙Feature的特殊处理当GooglePlay针对蓝牙功能来判断过滤时,它会使用比以上描述稍微不同的规则。
如果应用程序在其清单的一个<uses-permission>元素中声明了一个蓝牙权限,但没有明确的在<uses-feature>>元素中声明蓝牙Feature,那么GooglePlay会检查应用程序被设计成要运行在Android平台的哪个版本上,这个版本是在<uses-sdk>元素中被指定的。
如下表所示,GooglePlay只会在应用程序把Android2.0(APILeve5)或更高的版本作为最低版本或目标平台时,才会启用针对蓝牙功能的过滤。但是,要注意的是,当应用程序在<uses-feature>元素中明确声明了蓝牙Feature时,GooglePlay会使用普通的规则来进行过滤处理。
表1:GooglePlay如何判断申请了蓝牙权限但却没有在<uses-feature>元素中声明蓝牙Feature的应用程序的蓝牙Feature需求的:
如果minSdkVersion
或targetSdkVersion
结果
<=4 (或者uses-sdk没被申明)
<=4
对于任何报告其支持android.hardware.bluetoothFeature的设备,GooglePlay不会把应用程序过滤掉。
<=4
>=5
对于任何不支持android.hardware.bluetooth Feature的设备,GooglePlay都会把该应用程序过滤掉。
>=5
>=5
以下的例子,基于GooglePlay如何处理蓝牙Feature,演示了不同的过滤效果。
第一个例子中,应用程序被设计成要运行在比较旧的APILevel上并声明了蓝牙权限,但是它没有在其<uses-feature>元素中声明蓝牙Feature。结果:GooglePlay不会把该应用程序从任何设备上过滤掉。<manifest ...> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-sdk android:minSdkVersion="3" /> ... </manifest>第二个例子,相同的应用程序,还声明了一个目标APILevel是5的属性。结果:GooglePlay会假设应用程序需要蓝牙Feature,并把应用程序从那些没有报告支持蓝牙功能的设备上过滤掉,包括那些运行较旧平台版本的的设备。
<manifest ...> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="5" /> ... </manifest>这里,相同的应用程序,但声明的蓝牙Feature需求。结果:与第二个例子相同(过滤被应用)。
<manifest ...> <uses-feature android:name="android.hardware.bluetooth" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="5" /> ... </manifest>最后,上面的例子中,相同的应用程序,但添加了android:required="false"属性。结果:GooglePlay会针对所有设备禁止使用基于蓝牙Feature支持的过滤。
<manifest ...> <uses-feature android:name="android.hardware.bluetooth" android:required="false" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="5" /> ... </manifest>测试应用程序所需要的Feature
可以使用包含在AndroidSDK中的aapt工具,来判断GooglePlay会怎样过滤自己的应用程序(基于应用声明的Feature和Permission/权限)。用dump badging 命令来运行aapt工具,执行该项测试工作。aapt工具会解析应用程序的Manifest文件,并且使用与GooglPlay相同的规则,来判断应用程序所申请的Feature。
以下是使用这个工具的步骤:
首先,把应用程序作为一个未签名的..apk来编译并导出。如果使用带有ADT的Eclipse来开发应用程序,那么右击工程,并选择AndroidTools > Export Unsigned ApplicationPackage。选择目标文件名和路径,点击OK按钮。
接下来,如果在环境变量PATH中没有设置aapt的路径,定位找到它。如果使用的是SDK Toolsr8或更高的版本,那么可以在<SDK>/platform-tools/目录中找到aapt。
注意:所使用的aapt工具版本必须是提供给最新的可用的平台工具组件。如果没有,使用AndroidSDK Manager 来下载。
使用以下语法来运行aapt:
$ aapt dump badging <path_to_exported_.apk>
以下例子是针对上面第二个蓝牙的例子的命令输出:
$ ./aapt dump badging BTExample.apk package: name='com.example.android.btexample' versionCode='' versionName='' uses-permission:'android.permission.BLUETOOTH_ADMIN' uses-feature:'android.hardware.bluetooth' sdkVersion:'3' targetSdkVersion:'5' application: label='BT Example' icon='res/drawable/app_bt_ex.png' launchable activity name='com.example.android.btexample.MyActivity'label='' icon='' uses-feature:'android.hardware.touchscreen' main supports-screens: 'small' 'normal' 'large' locales: '--_--' densities: '160'