Setting up a Push Notification service on Windows Server 2003

转自: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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值