您的位置:首页 > 其它

Setting up a Push Notification service on Windows Server 2003

2012-09-11 19:23 537 查看
转自:http://x-cake.ning.com/profiles/blogs/setting-up-a-push-notification

Setting up a Push Notification service on Windows Server 2003

For this tutorial, I will be using IIS 6, SQL Server Express, and ASP.net (coded in CSharp).

I’m assuming you know how to set up and use SQL, IIS and ASP.net.

I've put up a good few code samples to get you started as well. I'm not sure if this info is still under NDA now that 3.0 is out, so I may have to remove it again if Apple don't like it.

It’s recommended that you run a service with a persistent connection to APNS.

I found a good tutorial on Windows Services and managed to write one up in a couple of
hours. You can use the code from below in your service (the new site doesn't seem to like code formatting. If anyone know of a better tag to get tabs and syntax highlighting, let me know).

Install SQL and ASP.net if you haven’t already done so and set up your site in IIS.

In SQL, you’ll need to store (at minimum) the unique device token that your app generates when it runs. This isn’t a fixed token and can change (e.g. on device restore) so be sure to record it each time the app is run. I tie the device token
to an account ID, but you could just as easily tie it to the UDID in the database.

Getting Started with Certs

In the iPhone Developer Program Portal create a new explicit App ID (com.mycompany.MyApp) and enable push for both Development & Production. This will generate two SSL Certs, which you should download and add to your login keychain.

Next, open Keychain Access and locate the two certs. Command-click on each cert and Export as .p12.

Upload both .p12 files to your server. If you double-click the two files, this will install them into the Current User’s Certificate Store. This is fine for testing, but you’ll want to store them in the Local Computer store if you want it to
work properly as a service.

Run MMC and add the Certificates snap-in, select Computer Account, then hit Finish on the next page. Hit OK to view the new snap-in.

Expand the Certificates (Local Computer) snap-in and right-click on Personal. Select All Tasks -> Import from the context menu. Locate your .p12 files and add them to the store.

Next, we need to allow the ASP.net service account access to these certs. I had a bit of trouble with this, but found doing all of the following worked:

a) To grant access to ASPNET account:

winhttpcertcfg -g -c LOCAL_MACHINE\MY -s MyCertificate -a ASPNET

b) To grant access to Network Service:

winhttpcertcfg -g -c LOCAL_MACHINE\MY -s MyCertificate -a "Network Service"

c) To grant access to Authenticated Users:

winhttpcertcfg -g -c LOCAL_MACHINE\MY -s MyCertificate -a "Authenticated Users"


where MyCertificate is the “Apple Production Push Services: ABCDEFGHIJ:KLMNOPQRST” text.

Make sure that you fully open ports 2195 (push server) and 2196 (feedback service) on your firewall.

Getting the Device Token in your iPhone App

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];

// launchOptions contains aps data (NSDictionary) if app was launched from notification alert

if (launchOptions)

{

if ([launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"])

{

if ([[launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"] objectForKey:@"aps"])

{

NSLog(@"Received Notification (Launch): %@", [launchOptions objectForKey:@"aps"]);

}

}

}

}

// Called if registration is successful

-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

// Store the device token in your online DB

// ...

}

// Called if we fail to register for a device token

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {

NSLog(@"Error in registration. Error: %@", error);

}

// Called if notification is received while app is active

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

NSLog(@"Received Notification (Active): %@", userInfo);

}


Coding the ASP.net / Windows Service

In your ASP.net code, you’ll need to open a secure socket connection to the APNS server - either gateway.sandbox.push.apple.com (development sandbox) or gateway.push.apple.com (production) on port 2195.

If you’ve signed your app using the Development provisioning profile, then it will only receive notifications sent to the sandbox server. Similarly, Production profiles only receive from the production server.

// Get the APNS cert

private X509Certificate getServerCert()

{

// Open the cert store on the Local Machine

X509Store store = new X509Store(StoreLocation.LocalMachine);

if (store != null)

{

// Store exists, so open it and search through the certs for the Apple cert

store.Open(OpenFlags.ReadOnly);

X509Certificate2Collection certs = store.Certificates;

if (certs.Count > 0)

{

int i;

for (i = 0; i < certs.Count; i++)

{

X509Certificate2 cert = certs[i];

if (cert.FriendlyName.Contains("Apple Production Push Services: ABCDEFGHIJ:KLMNOPQRST")))

{

// Cert found, so return it

return certs[i];

}

}

}

return null;

}

// Make the connection to the APNS server

public bool ConnectToAPNS()

{

X509Certificate2Collection certs = new X509Certificate2Collection();

// Add the Apple cert to our collection

certs.Add(getServerCert());

// Apple development server address

string apsHost;

if (getServerCert().ToString().Contains("Production"))

apsHost = "gateway.push.apple.com";

else

apsHost = "gateway.sandbox.push.apple.com";

// Create a TCP socket connection to the Apple server on port 2195

tcpClient = new TcpClient(apsHost, 2195);

// Create a new SSL stream over the connection

sslStream = new SslStream(tcpClient.GetStream());

// Authenticate using the Apple cert

sslStream.AuthenticateAsClient(apsHost, certs, SslProtocols.Default, false);

}


It’s recommended that you leave the socket open for as long as possible and just send push notifications as required:

// Used to convert device token from string to byte[]

private static byte[] HexToData(string hexString)

{

if (hexString == null)

return null;

if (hexString.Length % 2 == 1)

hexString = '0' + hexString; // Up to you whether to pad the first or last byte

byte[] data = new byte[hexString.Length / 2];

for (int i = 0; i < data.Length; i++)

data[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);

return data;

}

// Push a Hello World message to the device

public bool PushMessage()

{

String cToken = "yourdevicetoken...."

String cAlert = "Hello World!";

int iBadge = 1;

// Ready to create the push notification

byte[] buf = new byte[256];

MemoryStream ms = new MemoryStream();

BinaryWriter bw = new BinaryWriter(ms);

bw.Write(new byte[] { 0, 0, 32 });

byte[] deviceToken = HexToData(cToken);

bw.Write(deviceToken);

bw.Write((byte)0);

// Create the APNS payload - new.caf is an audio file saved in the application bundle on the device

string msg = "{\"aps\":{\"alert\":\"" + cAlert + "\",\"badge\":" + iBadge.ToString() + ",\"sound\":\"new.caf\"}}";

// Write the data out to the stream

bw.Write((byte)msg.Length);

bw.Write(msg.ToCharArray());

bw.Flush();

if (sslStream != null)

{

sslStream.Write(ms.ToArray());

return true;

}

return false;

}


Feedback Service

Make sure that you check the feedback service at least every hour to remove any user tokens owned by users who have uninstalled your app:

My feedback service code isn’t fully functional yet, so check out this hint on the developer forums:

https://devforums.apple.com/message/85206#85206

// Required because SSL connection cannot be established due to invalid cert warning.

public static bool ValidateServerCertificate(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)

{

return true

}

public String CheckFeedbackService()

{

System.Net.ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);

// Create an empty collection of certs

X509Certificate2Collection certs = new X509Certificate2Collection();

// Add the Apple cert to our collection

certs.Add(getServerCert());

// Apple feedback server address

string apsHostF;

if (getServerCert().ToString().Contains("Production"))

apsHostF = "feedback.push.apple.com";

else

apsHostF = "feedback.sandbox.push.apple.com";

// Create a TCP socket connection to the Apple server on port 2196

TcpClient tcpClientF = new TcpClient(apsHostF, 2196);

// Create a new SSL stream over the connection

SslStream sslStreamF = new SslStream(tcpClientF.GetStream(), true, new RemoteCertificateValidationCallback(ValidateServerCertificate));

try

{

// Authenticate using the Apple cert

sslStreamF.AuthenticateAsClient(apsHostF, certs, SslProtocols.Default, false);

//TODO: Read in data and remove device tokens if any found.

if (sslStreamF != null)

sslStreamF.Close();

if (tcpClientF != null)

tcpClientF.Close();

}

catch (AuthenticationException e)

{

Console.WriteLine("Authentication failed - closing the connection.");

sslStreamF.Close();

tcpClientF.Close();

return "NOAUTH";

}

finally

{

// The client stream will be closed with the sslStream

// because we specified this behavior when creating

// the sslStream.

sslStreamF.Close();

tcpClientF.Close();

}

return "";

}


Note: when testing this, you’ll need at least one other Push app installed on your device, otherwise the service will never know that your app has been uninstalled.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: