6. Selective targeting
As
mentioned earlier, some markets have more strict requirements for
content than others, and you have three choices for dealing with this:
-
Target the lowest common denominator and tailor your content to suit
all markets. This can get complicated if different markets have
conflicting requirements.
-
Build separate, tailored XAPs and their associated descriptions, tiles, and screenshots for each market.
-
Make your app available only for a selected subset of all possible markets.
The same kinds of choices apply for different devices. That is, some
devices have different capabilities than others: some support optional
sensors, others have more powerful cameras or front and/or back-facing
cameras. Another dimension to this is memory and processor power.
Devices range from 256 MB at the low end to 2 GB (currently) at the
high end, some devices have just a single-core processor, others have
dual-core processors, and processor speeds vary across devices. There’s
also an OS dimension here in that current Windows Phone 7 devices range
from 256 MB to 1 GB, whereas current Windows Phone 8 devices range from
512 MB to 2 GB.
The app manifest includes a Capabilities section in which you must specify all the capabilities that your app requires. There are three reasons for this:
-
So that the user can be informed of these capabilities by the
Windows Phone Store prior to installing your app. For example, if the
user sees that the app requires access to your contacts, you must
specify this in the Capabilities section with an ID_CAP_CONTACTS entry.
-
The security sandbox for your app is configured at runtime to
include only those capabilities that the app declares it uses. So, if
you don’t declare a capability that you’re using, the app will fail at
runtime.
-
For optional hardware capabilities, the Windows Phone Store will
filter the app catalog to match each device. For example, if a given
device does not have a compass, and your app requires one, your app
will not be available to that device.
As with content and markets, you can choose to build one app for the
lowest common denominator of device or multiple versions for different
device configurations. Or, you can make your app available only for a
selected subset of devices. You can achieve the first strategy by
simply eliminating any features that do not work on all devices in the
market. You can achieve the second by building and publishing multiple
XAPs. You can achieve the third by declaring appropriate capabilities
in your app manifest.
Another
option is to adapt your code dynamically to accommodate the constraints
of the device on which it’s running. Some hardware capabilities are optional, notably the gyroscope,
compass, and camera (front or back-facing). You can test for the
presence of each of these sensors and then take alternative code paths,
depending on the results. You can use the same technique for features
that the user can arbitrarily enable and disable, such as cellular data
connectivity and cellular data roaming. Figure 15 shows the OptionalCapabilities
app in the sample code, which makes use of these dynamic-discovery
techniques. This app merely displays the test results in the UI.
The app declares a number of data-bound TextBlock controls for each of the “yes/no” test results.
<TextBlock Text="{Binding Gyroscope, Converter={StaticResource converter}}"/>
Each TextBlock is data-bound to a property on a custom OptionalFeatures class, which exposes bool properties for whether or not the device supports a gyroscope, compass, and so on. The binding also uses a custom BoolToStringConverter for converting the bool values to “yes/no” strings.
public class OptionalFeatures : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
handler(this, new PropertyChangedEventArgs(propertyName));
}
private bool gyroscope;
public bool Gyroscope
{
get { return gyroscope; }
set
{
if (gyroscope != value)
{
gyroscope = value;
NotifyPropertyChanged("Gyroscope");
}
}
}
… other properties omitted for brevity.
}
In this app, when the user taps the app bar button, we gather all the optional capability information via tests such as Gyroscope.IsSupported or DeviceNetworkInformation.IsCellularDataEnabled and feed it into an OptionalFeatures object.
public OptionalFeatures Features { get; set; }
public MainPage()
{
InitializeComponent();
Features = new OptionalFeatures();
DataContext = Features;
}
private void appbarRefresh_Click(object sender, EventArgs e)
{
Features.Gyroscope = Gyroscope.IsSupported;
Features.Accelerometer = Accelerometer.IsSupported;
Features.Compass = Compass.IsSupported;
Features.PrimaryCamera = Camera.IsCameraTypeSupported(CameraType.Primary);
Features.FrontCamera = Camera.IsCameraTypeSupported(CameraType.FrontFacing);
Features.CellData = DeviceNetworkInformation.IsCellularDataEnabled;
Features.CellRoaming = DeviceNetworkInformation.IsCellularDataRoamingEnabled;
}