iOS推送通知我做错了啥? [关闭]

Posted

技术标签:

【中文标题】iOS推送通知我做错了啥? [关闭]【英文标题】:iOS Push Notification What am I doing wrong? [closed]iOS推送通知我做错了什么? [关闭] 【发布时间】:2012-12-15 01:04:59 【问题描述】:

我曾多次尝试向我的应用发送推送通知,但均无济于事。我遵循了许多教程并遵循了所有步骤。我从 APNS 服务器收到了成功的消息,但没有消息到达设备。我已经使用成功到达的开发证书测试了发送,并且我已经生成了适当的生产证书并在 php 脚本中使用它们。我将在下面发布我的代码。如果您发现我做错了什么,请告诉我。我只是不知道它是什么......

任何帮助将不胜感激。

<?php
$link=mysqli_connect('****','****','****','***');
if(mysqli_connect_errno())

    header('HTTP/1.1 400');
    header('Content-type: text/html');
    echo 'Connection Error: %s\n',mysqli_connect_error();
    exit;

echo "Connected to Database<br />";
echo "Querying Database<br />";
switch ($_REQUEST['App'])

    case "O2":
        $query="SELECT Token FROM O2CalculatorPushTokens";
        break;
    case "LZA":
        $query="SELECT Token FROM LZAPushTokens";
        break;
    case "MorseCode":
        $query="SELECT Token FROM MorseCodePushTokens";
        break;
    default:
        echo "Unknown App.";    
        exit;

$result=mysqli_query($link,$query);
echo mysqli_num_rows($result)."<br />";
if ($result==false)

    echo "No tokens to send to.";

else

    //Set SSL context
    $ctx = stream_context_create();
    echo "Loading SSL Certificate...<br>";
    switch($_REQUEST['App'])
    
        case "O2":
            stream_context_set_option($ctx, 'ssl', 'local_cert', 'SSL/O2CalculatorProductionSSL.pem');
            break;
        case "LZA":
            stream_context_set_option($ctx, 'ssl', 'local_cert', 'SSL/LandingZoneAssistantProductionSSL.pem');
            break;
        case "MorseCode":
            stream_context_set_option($ctx, 'ssl', 'local_cert', 'SSL/MorseCodeProductionSSL.pem');
            break;
        default:
            exit;
       
    echo "Unlocking SSL Certificate...<br><br>";
    stream_context_set_option($ctx, 'ssl', 'passphrase', '****');

    //Open a connection to the APNS server
    echo "Connecting to APNS server...<br>";
    $fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
    if(!$fp) exit("Failed to connect: $err $errstr<br><br>");
    else echo "Connected to APNS!<br />";

    //Create the payload body
    echo "Creating message...<br>";
    $body['aps'] = array('alert' => $_REQUEST['PushMessageTextArea']);
    echo $body."<br>";

    //Encode the payload as JSON
    echo "Encoding message...<br>";
    $payload = json_encode($body);
    echo $payload."<br>";

    while($row=mysqli_fetch_assoc($result))
    
        //Build the binary notification
        echo "Sending message to ".$row['Token']."<br>";
        $msg = chr(0).pack('n',32).pack('H*',$row['Token']).pack('n',strlen($payload)).$payload;
        //Send it to the server
        $PushResult = fwrite($fp, $msg, strlen($msg));
        if (!$PushResult) echo "Message not delivered! <br />";
        else echo "Message successfully delivered! <br />";
    ;

    //Close connection to the server
    echo "Closing APNS connection...<br><br>";
    fclose($fp);
    mysqli_free_result($result);

mysqli_close($link);

还有我的 iPhone 脚本...

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

// Override point for customization after application launch.

//Register for push notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert)];
return YES;

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

if (![[NSUserDefaults standardUserDefaults] boolForKey:@"registeredForPush"])

    //Remove spaces and brackets from deviceToken
    NSString* token  = [deviceToken description];
    token = [token stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];

    NSMutableString *params = [[NSMutableString alloc] initWithFormat:@"Token="];
    [params appendString:token];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.bluelineapps.net/****.php"] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:100.0];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    if (connection)
    
    //Show alert
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Thank you!" message:@"Thank you for registering for updates. Please rate this app in the AppStore after you've had some time to use it. Feedback is welcome and can be sent using the 'Feedback' tab below. Enjoy!" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
    [alert dismissWithClickedButtonIndex:0 animated:TRUE];
    [alert show];
    
    else
    
        //Show Error
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Registration error!" message:@"Failed to register for updates. Please try again later in your 'Settings' app. Sorry for the inconvenience." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
        [alert dismissWithClickedButtonIndex:0 animated:TRUE];
        [alert show];
    
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"registeredForPush"];
    [[NSUserDefaults standardUserDefaults] synchronize];



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

NSLog(@"Failed to get token, error: %@", error);


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

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Landing Zone Assistant" message:[userInfo valueForKeyPath:@"alert"] delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[alert show];


@end

更新:

好的,所以在删除所有 Mobile Provisioning 配置文件、所有证书、所有 .pem 文件、所有内容并为开发和生产重新生成所有证书、密钥、权限和配置文件之后,我的问题仍然存在......

使用沙盒网关向设备上的调试版本发送消息,成功。使用主苹果网关发送消息以在测试设备上发布 Ad Hoc 版本,不成功....

有什么想法吗?

我没有收到来自 APNS 服务的错​​误消息,一切顺利。没有构建错误。全新的最新证书...


更新:

我从 Apple 技术支持here 找到这篇文章,并按照所有步骤检查了所有内容。据我所知,一切都检查完毕。我的生产版本确实包含生产环境的 aps_environment。

我还发现 this method 用于生成 .pem 文件,这与我之前的尝试有些不同,所以我尝试了这个,但它仍然不起作用。我的代码仍然与上面相同,因为问题似乎出在其他地方,但是如果有人在扫描时看到某些东西,请告诉我。我只是想让这个工作。

我很乐意在这个问题上悬赏,但我没有足够的声誉,我一直试图通过帮助其他人解决问题来获得一些。


更新:

在搜索时,我发现了 Apple here 的另一份文档,其中有一行说明“请注意,生产环境中的设备令牌和开发(沙盒)环境中的设备令牌的值不同。 "所以我想另一个问题是。

开发和生产模式的 deviceToken 是否不同?


更新:

我知道这会越来越长,但我想展示我已采取哪些步骤来尝试自行解决此问题。

我一直在文档中看到这个 Entrust CA 证书弹出。我已经使用它来验证与 APNS 网关的连接,但是在发送推送消息时我没有在我的连接中使用它,因为我所见过的示例都没有显示使用它。这是必需的吗?如果需要,我该如何使用它?


更新:

我决定尝试使用 PhoneGap 重新开发我的应用程序并覆盖更多受众,因此我将暂时关闭它。感谢大家的帮助。

【问题讨论】:

所以您是说它适用于开发证书,但在使用生产证书时不起作用(即未收到消息)? AdHoc,可以使用Development Certificate 分发。为此,您不需要使用 main apple gateway。普通sandbox gateway就够了。 @arthan.v 太好了,不过我是通过 AppStore 分发的。这是否意味着我用 AdHoc 构建测试生产推送消息是徒劳的?在生产环境上线之前对其进行测试的最佳方法是什么? @SnareChops,我想这是不可能的。我只是在我的应用发布后才尝试push notification。大多数人都在做同样的事情。检查这些链接notification ex1,notification ex2 @arthan.v 那么也许是我上次推送更新时使用的旧配置文件没有apn-environment production 行,所以应用程序没有t 接收通知。如果我使用新的配置文件推送另一个更新,这可能会解决问题吗?此外,如果配置文件没有启用 apns,用户还会注册通知吗?我的数据库中充满了来自我的用户的令牌... 【参考方案1】:

在查看代码之前,打开生产配置文件并仔细检查它是否有条目:

    <key>ProvisionsAllDevices</key><true/>

我猜该设备已在开发配置文件中注册,因此它在那里工作但不适用于 prod 的事实让我相信问题出在配置文件本身。您必须拥有 Apple 的 Enterprise Developer 帐户才能创建可配置任何设备的配置文件。

【讨论】:

这似乎很奇怪,因为他们的说明和广告非常具有误导性。我假设您正在谈论 .mobileprovision 分发文件,它不包含该行。其他开发者如何使用 APNS 服务? 是的,这可能会造成混淆。正如您所发现的,使用您的标准开发者帐户,您可以配置已注册到该帐户的设备。假设作为开发人员,您将在这些设备上进行所有测试。为了将您的应用程序分发到任何设备,必须将其上传到 Apple 的 App Store,或者您必须购买企业帐户。如果您拥有 Enterprise 帐户,则可以创建和托管所谓的 Enterprise App Store,它允许您一起绕过 Apple App Store。 我们说的是同一件事吗?将我的应用程序分发给其他人或在他们的设备上运行时,我没有遇到问题。我和其他人一样通过 Apple App Store 销售我所有的应用程序。我也明白我只能在我向 XCode 注册的设备上测试我的应用程序。我遇到的问题是向已经拥有我的应用程序的用户发送 APNS 推送通知。这些也没有到达我的设备。因此,无论是 php 脚本还是 ios 脚本或两者的组合,都必须存在内部问题。

以上是关于iOS推送通知我做错了啥? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

XCode - 启用推送通知需要已添加 Apple ID

iOS 12 未收到 FCM 通知

IOS 通知显示两次默认和我的通知警报

ios swift使用啥推送通知? [关闭]

推送通知不适用于 FCM

Xamarin.iOS - 设备关闭时推送通知