Aplikacje Metro w JS - aplikacje trial i ze sprzedażą dodatków; integracja z Bing; globalizacja, lokalizacja, resources; sieć - izolacja, uprawnienia, sokety, syndykacja RSS/Atom (pobieranie, dodawanie, edytowanie, usuwanie wpisów), download i upload plików w tle, informacje o profilach połączeń (m.in koszty, limity, plan; notyfikacje).
In-app purchases and trial versions
Your customers can use your app for free during a trial period and you can design your app such that some features are limited or excluded until they pay for your app. You can also enable features, such as banners or watermarks, or ads that only appear during the trial, before the app is purchased.
The current license state of an app is stored as properties of the LicenseInformation class.
function appInit()
{
// some app initialization functions
// get current product object
// only one of these statements should be executed.
// the next line is commented out for testing but not for release
// currentProduct = Windows.ApplicationModel.Store.CurrentProduct;
// the next line is commented out for production/release but not for testing
currentProduct = Windows.ApplicationModel.Store.CurrentProductSimulator;
// we should have either a real or a simulated CurrentProduct object here.
// get the license information
licenseInformation = currentProduct.licenseInformation;
// register license state change
licenseInformation.onlicensechanged += reloadLicense;
// other app initializations function
}
function reloadLicense()
{
// app features to update when the license changes.
if (licenseInformation.isActive)
{
if (licenseInformation.isTrial)
{
// show feature that is available during trial only
}
else
{
// show feature that is available only with a full license
}
}
else
{
// an inactive license only occurs when there's an error
}
}
Your app can offer features that your customers can purchase from within the app, as opposed to having to buy them from the store. These in-app offers must be added to your app before you submit the app to the Windows Store.
Features enabled through in-app purchases can work for as long as the customer has a valid license for their app, or they can be limited in some way. The License API supports a time limit where the feature can work for a number of days that are configured when you describe your app. You can also implement other limits, such as limiting the number of times the feature is used.
For each feature that you want to make available through an in-app purchase transaction, create an in-app offer and add it to your app.
- Create an in-app offer token. Each in-app offer is uniquely identified in your app by an in-app offer token. The token is a string that you define and use in your app to identify a specific in-app offer.
- Code the feature in a conditional block. Each feature that is associated with an in-app offer must be in a conditional block that tests to see if the customer has a license to use that feature.
if (licenseInformation.featureLicenses.lookup("feature1").isActive)
{
// the customer can access this feature
}
else
{
// the customer cannot access this feature
}
Your app must also provide a way for your customers to buy the feature. Your customers can't use the store to make in-app purchases, like they did when they acquired your app.
function buyFeature1() {
if (!licenseInformation.featureLicenses.lookup("feature1").isActive)
{
// the customer doesn't own this feature so
// show the purchase dialog
currentProduct.requestFeaturePurchaseAsync("feature2").then(
function () {
// the in-app purchase was successful
},
function () {
// the in-app purchase was not completed because it
// was cancelled there was an error
});
}
else
{
// the customer already owns this feature
}
}
Integrating with Bing Search
You can integrate your Metro style app with Bing search by implementing a protocol handler in the app. This makes it possible for Bing to activate your app directly from search results. If you have a web site that is associated with your app, you can configure it such that your app will also appear in search results that list your web site.
To make it possible for Bing to launch your app from its search results, you need to create a protocol and add support for that protocol to your app. The format of the protocol that you create is similar to the HTTP protocol; however, instead of using http as the prefix, you would create your own prefix. For example, if your company was named Contoso, you might create a protocol prefix such as: contoso://
- Add a protocol handler to your app using the protocol you created for your app.
- Bing will pass the url and the query parameters to your app using the protocol that you created. url contains the deep link to the page in your site that appeared in the search results for your app to use. Your app would normally read this link and open the specific topic or page that it refers to. query contains the search string that was used to locate the search results. You can use that to take the user to the appropriate page in your app and to collect business intelligence (BI) data about how people are finding your apps.
- When the search results include a page from your website, Bing will provide the option for the user to see this result in your app. If they select that option, Bing will activate your app and pass it the string that contains the elements for your protocol handler, such as:
contoso://bing/search?url=http://www.contoso.com/contents/topic12345/&query=contosos%20coolest%20content
After you have added the protocol handler to your app, you'll need to configure Bing to be aware that your site can show results in an app (Bing webmaster).
Globalizing
Localize strings for different languages and markets
- Copy all strings from code and/or markup into a resource file (ResW or ResJSON), providing resource comments as necessary.
- Add resource references in the code and markup to refer to the resource.
- Isolate localizable resource files (for example, images that contain localizable strings, or that should be mirrored (Left-To-Right/Right-To-Left)) from language-neutral files, placing them in BCP-47 language tag named folders (such as fr-FR/logo.jpg).
- If localizing HTML, add the res.js file from the Windows Library for JavaScript to the document and make a call to WinJS.Resources.processAll on DOMContentLoaded.
- Be sure to build the package using Visual Studio.
Customize images for different resolutions
- Create three copies of each image: Original size for a typical 96dpi device, 140% the original size (f.e, a 100x100px image should also have a 140x140px image version), 180% the original size (f.e, a 100x100px image should also have a 180x180px image version)
- Name the images <name>.scale-100.<ext>, <name>.scale-140.<ext>, and <name>.scale-180.<ext> and place them side by side in the same folder, where <name>.<ext> is the name of the image as referenced in code/markup. For example, <img src=”logo.jpg” /> and the package contains logo.scale-100.jpg and logo.scale-150.jpg.
- Be sure to build the package using Visual Studio or MSBuild.
Use resources
Referring to resources in HTML markup is similar to Windows Library for JavaScript data-binding for HTML. HTML elements should have an additional data-win-res attribute specifying the properties of the element and the names of the resources that should replace them.
<input type="text" placeholder="Click here" title="Tooltip Info" />
<ul>
<li>Male</li>
<li>Female</li>
</ul>
<input type="text" placeholder="" title=" " data-win-res="placeholder:Placeholder1; title: Title1"/>
<ul>
<li data-win-res="textContent:ListElement1"></li>
<li data-win-res="textContent:ListElement2"></li>
</ul>
The resource file (en-US/resources.resjson) contains:
{
"Placeholder1" : "Click here",
"Title1" : "Tooltip Info",
"ListElement1" : "Male",
"ListElement2" : "Female"
}After translation occurs, a corresponding resources.resjson file should be created for each language (for example, es-MX/resources.resjson).
In order to process these data-win-res attributes, the document must include a Windows Library for JavaScript toolkit called Res.js, which exposes a processAll call. It is recommended that this process call be one of the first calls made after the DOMContentLoaded event, as it is critical to the document's UI displaying properly.
<script type="text/javascript" src="/winjs/js/Res.js" />
<script type="text/javascript">
WinJS.Application.onloaded = function() {
WinJS.Resources.processAll();
}, false);
</script>
A replaceable string can contain markup if necessary.
{
"string1" : "Hello <strong>World</strong>"
}If the string does not contain any markup, then bind the resource wherever possible to the textContent property instead of innerHTML. The textContent property is much faster to replace than innerHTML.
Resources can also be accessed from JavaScript as well as HTML. The simplest way to access resources is through the Windows.ApplicationModel.Resources.ResourceLoader APIs in Windows Runtime.
el.innerHTML = 'Hello World';
var R = new Windows.ApplicationModel.Resources.ResourceLoader();
el.innerHTML = R.getString('HelloWorld');
where HelloWorld is the name of the string "Hello World" in the resource.resw or resource.resjson file.
Networking
You can retrieve RSS feeds, connect your users' devices to nearby devices, and send real-time status and notifications to wake up for applications. Because Metro style apps are always connected, always on, Windows Developer Preview helps you manage your users' resources by getting network connection and cost information apps that can use network resources in ways that minimize costs. You also get support for uninterrupted, cost-aware and resume-able downloading and uploading of large content.
Networking allows communication with remote endpoints on the Internet or on private networks. If a higher-layer protocol is not available for your feature, you can use UDP (datagram), TCP (stream sockets), or WebSockets. The Windows Developer Preview introduces a new type of socket, a WebSocket.
The following networking features are supported:
- Publishing and syndication - Support for retrieving feeds in the RSS or Atom format across multiple versions. The AtomPub protocol is supported as well to support publishing Atom collections. These APIs make it easy to implement support for newer formats such as OData. This feature is implemented in the Windows.Web.Syndication and Windows.Web.AtomPub namespaces.
- Download and upload - Support for uninterrupted, cost-aware and resumable downloading and uploading of large content, even when the calling application is not in the foreground. These APIs supports download using HTTP, HTTPS, FTP protocols and using the File schema. This feature is implemented in the Windows.Networking.BackgroundTransfer namespace.
- Network cost, connectivity, and status management - Support for retrieving network connection and cost information allow apps to make intelligent management decisions on using network resources in ways that minimize cost. This feature is implemented in the Windows.Networking.Connectivity namespace.
- Mobile broadband account management - Support for managing mobile broadband accounts allows an app to make intelligent management decisions. This feature is implemented in the Windows.Networking.NetworkOperators namespace.
- Proximity - Enables a Metro style app to connect computers with a simple tap gesture. If two computers come within close proximity of each other, or are tapped together, the operating system becomes aware of the nearby computer. Your app can then establish a connection between the two computers to share content such as photos or links, create a multi-player experience, or publish and subscribe to messages when the computers are tapped together. This feature is implemented in the Windows.Networking.Proximity namespace.
- Notifications - Support for the use of notification channels to enable real-time status and notifications to wake applications that are always on and always connected. This feature is implemented in the Windows.Networking.Sockets and Windows.Networking.PushNotifications namespaces.
- TCP/UDP Client and listener - This feature is implemented in the Windows.Networking.Sockets and Windows.Networking namespaces.
- WebSockets - This feature is implemented in the Windows.Networking.Sockets and Windows.Networking namespaces.
Network isolation
Not all apps require access to the network, however for apps that do, the Windows Developer Preview provides different levels of network access that can be enabled by selecting appropriate capabilities. Network isolation allows you to define the scope of required network access for each app. Network access requests are divided into two categories:
- Outbound client-initiated requests - The app acts as the client and initiates network access by sending an initial network request to a remote computer, usually a server. The client app sends one or more requests to the server and the server sends back a single response or several responses to the client app. All traffic from a web client app to a web server would be in this category.
- Inbound unsolicited requests - The app acts as a network server and listens for inbound network requests from a remote computer. The remote computer initiates network access by sending an initial request to the app, which acts as server. The remote computer sends one or more requests to the app, which sends back one or more responses to the remote computer. An app that functions as a media server would be in this category.
An app with an undefined scope is prevented from accessing the specified type of network connection. The ability to set and enforce network isolation ensures that if an app gets compromised, it can only access networks where the app has explicitly been granted access.
The following are the network boundaries the system will look for: Home\Work Network, Internet.
The following networking isolation capabilities are defined:
- Internet (Client) - the internetClient capability in the app manifest
- Internet (Client and Server) - inbound access to critical ports are always blocked. This is the internetClientServer capability in the app manifest.
- Home\Work Networking - inbound and outbound network access at the user's trusted places, like home and work. Inbound access to critical ports are always blocked. This is the privateNetworkClientServer capability in the app manifest.
Certain other capabilities may need to be enabled in the app manifest for network access. These capabilities are defined as GUIDs, which are used to enforce the boundaries:
- Default Windows Credentials - allows an app to connect to network resources that require domain credentials. This capability will require a domain administrator to enable the functionality for all apps. An app with this capability can impersonate you on the network. This is the defaultWindowsCredentials capability in the app manifest.
- Proximity - the proximity capability in the app manifest.
- Shared User Certificates - allows an app to access software and hardware certificates, such as smart card certificates. When this capability is invoked at runtime, the user must take action, such as inserting a card or selecting a certificate. With this capability, your software and hardware certificates or a smart card are used for identification in the app (f.e bank, government, employer). This is the sharedUserCertificates capability in the app manifest.
Certain device capabilities that are related to device access may also need to be enabled in the app manifest for network access to function as expected.
- Webcam – provides access to a webcam's video feed. This capability is needed if the app intends to share a webcam's video feed with a remote computer over the network. This is the webcam capability in the app manifest.
When the proximity capability is enabled in an app manifest, there is no need for any additional networking capability to be enabled. The user must still consent to send or accept an invite from the proximity device to allow communication between the proximity device and the local computer.
A built in diagnostic tool, CheckNetIsolation.exe, is provided to help developers test, diagnose and troubleshoot an app that requires network capabilities. CheckNetIsolation.exe is a command line tool that takes input parameters from the command line.
Sockets
This feature includes TCP and UDP sockets including UDP multicast to enable developers to implement other higher-layer networking protocols. TCP and UDP sockets can be used by an app to make client connections, to listen for connections and operate as a server, or for both client and server operations.
Representational State Transfer (REST) APIs that are available using C#, VB.NET, and C++ .
A stream socket
You can use TCP to perform network data transfers with a stream socket.
Select the Internet (Client) and Home/Work Networking capabilities.
var listener = null;
var clientSocket = null;
function createServer() {
var serviceName = document.getElementById("clientServiceName").value;
listener = new Windows.Networking.Sockets.StreamSocketListener (serviceName);
listener.acceptAsync().then(
function (serverSocket) {
log("server: accepted new socket");
var dr = new Windows.Storage.Streams.DataReader (serverSocket.inputStream);
dr.inputStreamOptions = Windows.Storage.Streams.InputStreamOptions.partial;
dr.loadAsync (64*1024).then (
function (nbytes) {
log ("server: read in data");
var string = dr.readString(nbytes);
log ("server: got string " + string);
}, onError);
}, onError);
log("server: created listener")
}
function connectClient() {
clientSocket = new Windows.Networking.Sockets.StreamSocket;
var hostName = document.getElementById("clientHostName").value;
var serviceName = document.getElementById("clientServiceName").value;
clientSocket.connectAsync(new Windows.Networking.HostName(hostName), serviceName, Windows.Networking.Sockets.SocketProtectionLevel.plainSocket).then(onClientAccept, onError);
log("client: created client socket ok");
}
function sendString() {
if (!clientSocket || !clientSocket.outputStream) {
return;
}
var dw = new Windows.Storage.Streams.DataWriter(clientSocket.outputStream);
dw.writeString("Hello World!");
dw.storeAsync().then();
log("client: send string");
}
function closeAll() {
if (listener) {
listener.close();
listener = null;
}
if (clientSocket) {
clientSocket.close();
clientSocket = null;
}
}
Web content syndication (RSS/Atom)
Accessing a web feed
The Windows Runtime supports feed retrieval for RSS format standards from 0.91 to RSS 2.0, and Atom standards from 0.3 to 1.0. The Windows.Web.Syndication classes used to define feeds and feed items are capable of representing both RSS and Atom elements equally.
Additionally, Atom 1.0 and RSS 2.0 formats both allow their feed documents to contain elements or attributes not defined in the official specifications. Over time, these custom elements and attributes have become a way to define domain specific information consumed by other data services, like GData and OData. To support this now common functionality, the Windows Runtime defines the SyndicationAttribute class for attributes, and the SyndicationNode class for generic XML elements.
Presenting the feed content represented by a SyndicationItem object will differ depending on the feed format. It is recommended that SyndicationItem.Summary is accessed for Atom feeds, and SyndicationItem.Content for RSS feeds.
function getFeedWithSyndicationClient(feedUriString) {
var client = new Windows.Web.Syndication.SyndicationClient();
var feedUri = new Windows.Foundation.Uri (feedUriString);
var rfo = client.RetrieveFeedAsync(feedUri);
rfo.Completed = function () {
var feed = rfo.GetResults();
for (var i = 0; i < feed.Items.Size; i++) {
var item = items.GetAt(i);
print("The item is: " + item.Id);
print("The item's content is: " + item.Content.Text);
}
};
rfo.Start();
}
Web syndication
The Windows.Web.AtomPub namespace defines the classes used to access a service document and modify the feed resources it contains. However, the Windows.Web.Syndication namespace defines the classes used for individual feeds, feed entries, and content elements.
Creating a new feed and feed entry
function createResourceWithAtomPubClient(docUriString) {
//Initialize the AtomPubClient
var client = new Windows.Web.AtomPub.AtomPubClient();
//Create Uri object for the service document
var docUri = new Windows.Foundation.Uri (docUriString);
//Retrieve the service document using the Uri
var rsd = client.RetrieveServiceDocumentAsync(docUri);
rsd.Completed = function () {
var doc = rsd.GetResults();
//Define the feed Uri.
var feedUri = doc.Workspaces.GetAt(0).Collections.GetAt(0).Uri;
//Create and populate the new feed entry.
var item = new Windows.Web.Syndication.SyndicationItem();
item.Authors.SetAt(0, new Windows.Web.Syndication.SyndicationPerson("name", "alias@hotmail.com"));
item.Content = new Windows.Web.Syndication.SyndicationContent("discussion at 3:00pm", 0);
//Finalize the new entry.
rsd = client.CreateResourceAsync(feedUri, "meeting", item);
rsd.Completed = function () {
var newItem = rsd.GetResults();
print("The new item is: " + newItem.Id);
print("The new item's content is: " + newItem.Content.Text);
};
rsd.Start();
};
rsd.Start();
}
Retrieving and updating an existing feed entry
function updateResourceWithAtomPubClient(docUriString) {
//Initialize the AtomPubClient
var client = new Windows.Web.AtomPub.AtomPubClient();
//Create Uri object for the service document
var docUri = new Windows.Foundation.Uri (docUriString);
//Retrieve the service document using the Uri
var rsd = client.RetrieveServiceDocumentAsync(docUri);
rsd.Completed = function () {
var doc = rsd.GetResults();
var feedUri = doc.Workspaces.GetAt(0).Collections.GetAt(0).Uri;
//Retrieve the feed.
rsd = client.RetrieveFeedAsync(feedUri);
rsd.Completed = function () {
var feed = rsd.GetResults();
//Create a new SyndicationContent object to replace the previous.
feed.Items.GetAt(0).Content = new Windows.Web.Syndication.SyndicationContent("discussion at 4:00pm", 0);
//Finalize the update the feed entry.
rsd = client.UpdateResourceAsync(feed.Items.GetAt(0));
rsd.Completed = function () {
var updatedItem = rsd.GetResults();
print("The updated item is: " + updatedItem.Id);
print("The updated item's content is: " + updatedItem.Content.Text);
};
rsd.Start();
};
rsd.Start();
};
rsd.Start();
}
Locating and removing an existing feed entry
function deleteResourceWithAtomPubClient(docUriString) {
//Initialize the AtomPubClient
var client = new Windows.Web.AtomPub.AtomPubClient();
//Create Uri object for the service document
var docUri = new Windows.Foundation.Uri (docUriString);
//Retrieve the service document using the Uri
var rsd = client.RetrieveServiceDocumentAsync(docUri);
rsd.Completed = function () {
var doc = rsd.GetResults();
var feedUri = doc.Workspaces.GetAt(0).Collections.GetAt(0).Uri;
rsd = client.RetrieveFeedAsync(feedUri);
rsd.Completed = function () {
rsd = client.DeleteResourceAsync(feed.Items.GetAt(0).EditUri);
rsd.Completed = function () {
print("The item was deleted");
};
rsd.Start();
}
rsd.Start();
};
rsd.Start();
}
Download and upload
Use the Windows.Networking.BackgroundTransfer namespace provided in the Windows Runtime environment to enhance your Metro style app with advanced download/upload features that allow for transfers to be recovered, resumed, and managed in the background. Additionally, this feature leverages network-cost information provided by the Connectivity feature during transfer operations.
When a Metro style app uses the Windows.Networking.BackgroundTransfer namespace to initiate a download or upload, the request is configured and initialized using BackgroundDownloader or BackgroundUploader class objects. Each transfer operation is individually sand-boxed in the background, separate from the calling app, and will run parallel to any other transfers. Progress information is available for display through an app UI, and depending on the scenario, you can enable the app to pause, resume, cancel, or even read from a file during transfer. This sand-boxed operational environment promotes smart power usage and prevents the problems that can arise when a connected app encounters events like unexpected shutdowns or sudden network status changes.
The Background Transfer feature provides methods that support basic server authentication credentials, but also supports the use of custom HTTP headers (via SetRequestHeader) for each transfer operation. For example, a custom header can provide for more advanced authentication methods such as cookies, Kerberos, digest, NTLM, negotiate, forms based authentication, or OAuth tokens.
The Background Transfer feature maintains the integrity of each file transfer operation when network status changes occur, intelligently leveraging connectivity and carrier data-plan status information provided by the Network Connectivity feature for each connection established on the machine.
For example, download transfers are paused automatically when a user hits a carrier-defined data cap in order to prevent additional charges during the current billing cycle, with the the paused transfer automatically resuming when a connection to a "unrestricted" network has been established.
Finally, after a user logs in after the machine is unexpectedly shutdown, download transfers persist through machine restarts and will re-initiate in the background. Incomplete download transfers will resume as soon as appropriate network conditions are available.
function DownloadOperation() {
var operation;
var imageStream = null;
this.start = function (fileName, uriString) {
try {
// Asynchronously create file in pictures folder.
Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(fileName).then(function (newFile) {
var uri = Windows.Foundation.Uri(uriString);
var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
print("Using URI: " + uriString + "<br/>");
// Pass uri and file handle to function and start download asynchronously.
var promise = downloader.startDownloadAsync(uri, newFile);
// Persist download operation in class.
operation = promise.operation;
// Assign callbacks associated with download.
promise.then(complete, error, progress);
});
} catch (err) {
mySample.displayError("Error in DownloadOperation.start: " + err);
}
};
// Progress callback.
function progress(p) {
try {
// Output all attributes of the progress parameter.
print("<b>" + operation.guid + " - Progress:</b>");
for (var att in p) {
print(att + ": " + p[att] + ", ");
}
print("<br/>");
// Handle various pause status conditions.
if (p.status === Windows.Networking.BackgroundTransfer.BackgroundTransferStatus.pausedByApplication) {
print("Download " + operation.guid + " paused by application <br\>");
} else if (p.status === Windows.Networking.BackgroundTransfer.BackgroundTransferStatus.pausedCostedNetwork) {
print("Download " + operation.guid + " paused because of costed network <br\>");
} else if (p.status === Windows.Networking.BackgroundTransfer.BackgroundTransferStatus.pausedNoNetwork) {
print("Download " + operation.guid + " paused because network is unavailable.<br\>");
} else {
// A response is required before assigning the result stream to the image. When a response is received from
// the server (hasResponseChanged == true) and if the stream hasn't been assigned yet
// (imageStream == null), then assign the stream to the image.
if ((p.hasResponseChanged && imageStream === null)) {
try {
// Get Content-Type response header.
var contentType = operation.getResponseInformation().headers.lookup("Content-Type");
// Get stream starting from byte 0.
imageStream = operation.getResultStreamAt(0);
// Convert stream to MS-Stream.
var msStream = msWWA.createStreamFromInputStream(contentType, imageStream);
var imageUrl = URL.createObjectURL(msStream);
// Pass stream URL to HTML image tag.
id("scenario1ImageHolder1").src = imageUrl;
} catch (err) {
print("<b>Error in outputting file:</b> " + err + "<br\>");
}
}
}
} catch (err) {
mySample.displayError("Error in DownloadOperation.progress: " + err);
}
}
}
function downloadFile() {
var firstDownload = new DownloadOperation();
// Pass file name to be stored on disk to start download.
firstDownload.start("1.png", "http://localhost/squareTile-sdk.png");
}
It is important to note that upload operations cannot be paused or resumed; retrying an interrupted upload requires the initialization of a new operation.
function UploadFile() {
try {
// Setup Picker
var openpicker = new Windows.Storage.FileOpenPicker();
openpicker.fileTypeFilter.replaceAll([".png", ".jpg", ".bmp"]);
// Setup uploader
var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
uploader.setMethod("POST");
// Setup server - code here depends on type of destination.
// "<Placeholder>" is shown as the URI in this example, but this is also an opportunity to include OAuth info, etc.
var destinationUri = new Windows.Foundation.Uri("<Placeholder>");
// Call Picker to choose file to upload
openpicker.pickSingleFileAsync().then(function (file) {
// Set file to upload and begin upload
uploader.setSourceFile(file);
uploader.setRequestHeader("Filename", file.fileName);
promiseUI = uploader.startUploadAsync(destinationUri)
return promiseUI;
}).then(onComplete, onError);
} catch (e) {
mySample.displayStatus(e);
}
}
Leveraging available network connection information
Each network connection on a machine has a connection profile that provides information on connectivity, network cost, and data usage. This connection information is especially relevant for Metro style apps designed to run on devices that routinely traverse multiple networks, many of which are metered networks.
The information provided by each connection profile covers a lot of ground. Which data proves the most useful depends on the nature of the primary feature of the app leveraging it. For example, an app that streams video from the Web can monitor the inbound bits per second over the connection to predict and compensate for an impact on stream quality. Another example is a download app designed for mobile devices that monitors the data plan restrictions associated with the device's connection to the Web, preventing unexpected carrier service fees.
A Metro style app that connects to destinations on the Web should obtain cost information and status change events for the network on which they are sending/receiving data using the Network Information APIs.
NetworkCostType
Unrestricted
Variable/Approaching Data Cap
- Delay or schedule lower priority operations until an unrestricted network is available.
- When streaming content to a user, such as a movie or a video, use a lower bit-rate. For example, if your app is streaming HD-Quality video, stream Standard Definition when on a metered network.
- Use less bandwidth. For example, switching to header-only mode when receiving emails.
- Use the network less frequently. An example solution is to reduce the frequency of any polling operations for syndicating news feeds, refreshing content for a website, or getting web notifications.
- Allow users to explicitly choose to stream HD-Quality video, retrieve full emails, download lower priority updates, etc.., rather than doing so by default.
- Explicitly ask for user permission prior to using the network.
Unknown - as an unrestricted network
Maintaining a reliable connection to the Web
One of the most fundamental ways your app can demonstrate agility in the network space is by maintaining a consistent level of quality when interfacing with the Web. This can be done by leveraging the information provided by the connection profile and subsequent network status change notifications and by identifying available networks that meets current requirements.
Windows will automatically use the lowest cost network available.
var networkInfo = Windows.Networking.Connectivity.NetworkInformation;
var networkCostInfo = Windows.Networking.Connectivity.NetworkCostType;
//Indicates if the connection profile is registered for network status change events. Set the default value to FALSE.
var registeredNetworkStatusNotif = false;
//Used to store network status change information for, in the following examples, the internet connected profile.
var internetProfileInfo = "";Retrieving all network connection profiles
Calling the GetConnectionProfiles method retrieves the ConnectionProfile for each connection currently established on the machine.
function DisplayConnectionProfileList() {
var profileList = "";
try {
var ConnectionProfiles = networkInfo.getConnectionProfiles();
if (ConnectionProfiles.length != 0) {
for (var i = 0; i < ConnectionProfiles.length; i++) {
//Display Connection profile info for each profile
profileList += GetConnectionProfileInfo(ConnectionProfiles[i]);
profileList += "-------------------------------------------------------------\n\r";
}
mySample.displayStatus(profileList);
}
else {
mySample.displayStatus("No profiles found");
}
}
catch (e) {
mySample.displayError("Exception Caught: " + e + "\n\r");
}
}
Alternately, calling GetInternetConnectionProfile will retrieve only the profile associated with the connection currently being used for Web connectivity.
function DisplayInternetConnectionProfileInfo() {
try {
// get the ConnectionProfile that is currently used to connect to the Internet
var internetProfile = networkInfo.getInternetConnectionProfile();
mySample.displayStatus(GetConnectionProfileInfo(internetProfile));
}
catch (e) {
mySample.displayError("Exception Caught: " + e + "\n\r");
}
}
Displaying usage and data plan status information for a connection profile
Each ConnectionProfile provides the following connection details:
- ConnectionCost - Provides connection cost information details, including data limit and roaming information.
- NetworkCostType
- DataPlanStatus, DataPlanUsage
- DataUsage - Provides local connection usage information.
- NetworkAdapter
function GetConnectionProfileInfo(connectionProfile) {
try {
if (connectionProfile == null) {
return "";
}
var returnString = "ProfileName: " + connectionProfile.profileName + "\n\r";
returnString += "Connected: " + connectionProfile.connected + "\n\r";
//Display Connection cost info
returnString += "Connection Cost Information:\n\r";
returnString += "===============\n\r";
var connectionCost = connectionProfile.getConnectionCost();
returnString += "Cost Type: " + GetCostType(connectionCost.networkCostType) + "\n\r";
returnString += "Roaming: " + connectionCost.roaming + "\n\r";
returnString += "Over Datalimit: " + connectionCost.overDataLimit + "\n\r";
returnString += "Approaching Datalimit: " + connectionCost.approachingDataLimit + "\n\r";
//Display Dataplan status info
returnString += "Dataplan Status Information:\n\r";
returnString += "===============\n\r";
var dataPlanStatus = connectionProfile.getDataPlanStatus();
if (dataPlanStatus.dataPlanUsage != null) {
returnString += "Usage In Megabytes: " + dataPlanStatus.dataPlanUsage.megabytesUsed + "\n\r";
returnString += "Last Sync Time: " + dataPlanStatus.dataPlanUsage.lastSyncTime + "\n\r";
}
else {
returnString += "Dataplan Usage: " + "Not Defined" + "\n\r";
}
if (dataPlanStatus.InboundBitsPerSecond != null) {
returnString += "Inbound Bits Per Second: " + dataPlanStatus.InboundBitsPerSecond + "\n\r";
}
else {
returnString += "Inbound Bits Per Second: " + "Not Defined" + "\n\r";
}
if (dataPlanStatus.OutboundBitsPerSecond != null) {
returnString += "Outbound Bits Per Second: " + dataPlanStatus.OutboundBitsPerSecond + "\n\r";
}
else {
returnString += "Outbound Bits Per Second: " + "Not Defined" + "\n\r";
}
if (dataPlanStatus.dataLimitInMegabytes != null) {
returnString += "Data Limit In Megabytes: " + dataPlanStatus.dataLimitInMegabytes + "\n\r";
}
else {
returnString += "Data Limit In Megabytes: " + "Not Defined" + "\n\r";
}
if (dataPlanStatus.nextBillingCycle != null) {
returnString += "Next Billing Cycle: " + dataPlanStatus.nextBillingCycle + "\n\r";
}
else {
returnString += "Next Billing Cycle: " + "Not Defined" + "\n\r";
}
if (dataPlanStatus.maxDownloadFileSizeInMegabytes != null) {
returnString += "Maximum Download File Size in Megabytes: " + dataPlanStatus.maxDownloadFileSizeInMegabytes + "\n\r";
}
else {
returnString += "Maximum Download File Size in Megabytes: " + "Not Defined" + "\n\r";
}
returnString += "Cost Based Suggestions: " + CostBasedSuggestions(connectionCost) + "\n\r";
}
catch (e) {
mySample.displayError("Exception Caught: " + e + "\n\r");
}
return returnString;
}
Registering for network status change notifications
function RegisterForNetworkStatusChangeNotif() {
try {
// register for network status change notifications
if (!registeredNetworkStatusNotif) {
networkInfo.addEventListener("networkstatuschanged", OnNetworkStatusChange);
registeredNetworkStatusNotif = true;
}
if (internetProfileInfo == "") {
mySample.displayStatus("No network status change. ");
}
}
catch (e) {
mySample.displayError("Exception Caught: " + e + "\n\r");
}
}
function OnNetworkStatusChange(sender) {
var internetProfileInfo = "";
try {
//network status changed
internetProfileInfo = "Network Status Changed: \n\r";
// get the ConnectionProfile that is currently used to connect to the Internet
var internetProfile = networkInfo.getInternetConnectionProfile();
internetProfileInfo += GetConnectionProfileInfo(internetProfile) + "\n\r";
mySample.displayStatus(internetProfileInfo);
internetProfileInfo = "";
}
catch (e) {
mySample.displayError("Exception Caught: " + e + "\n\r");
}
}
c.d.n
Brak komentarzy:
Prześlij komentarz