调用Google Play订阅API时用户姓名邮箱字段返回null问题求助
我来帮你分析下这个棘手的问题——你调用Google Play的Purchases.Subscriptions.Get接口时,EmailAddress、GivenName和FamilyName字段始终返回null,但其他购买信息(比如价格、国家代码)都显示正常,对吧?这其实是Google Play隐私机制导致的,咱们一步步来拆解解决:
问题背景
你的Android应用Akita Security(包名com.highiot.mob)提供订阅购买服务,用户完成购买后你拿到了purchase token,但调用API查询用户个人信息时,核心的身份字段全部为空。
相关代码片段
应用内购买代码(Xamarin)
private async void Purcase(string productId) { try { var connected = await CrossInAppBilling.Current.ConnectAsync(); if (!connected) { //Couldn't connect to billing, could be offline, alert user return; } //try to purchase item CrossInAppBilling.Current.InTestingMode = true; var purchase = await CrossInAppBilling.Current.PurchaseAsync(productId, ItemType.Subscription, "apppayload"); if (purchase == null) { //Not purchased, alert the user } else { //Purchased, save this information var id = purchase.Id; var token = purchase.PurchaseToken; var state = purchase.State; bool status = false; if (state == PurchaseState.PaymentPending) { status = true; } ViewModel.SendSubscription(productId, token, "Google", status); } } catch (Exception ex) { //Something bad has occurred, alert user } finally { //Disconnect, it is okay if we never connected await CrossInAppBilling.Current.DisconnectAsync(); } }
Google API调用代码
static async Task Main(string[] args) { bool acknowledge = false; string projectId = "robotic-circle-243009"; string subscriptionId = "highiot-admin-api"; var _credentialsJson = "HighIoT_key.json"; Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _credentialsJson)); SubscriptionName subscriptionName = new SubscriptionName(projectId, subscriptionId); SubscriberClient subscriber = await SubscriberClient.CreateAsync(subscriptionName); GoogleCredential credentialsPlay; using (var key = new FileStream(_credentialsJson, FileMode.Open, FileAccess.Read)) credentialsPlay = GoogleCredential.FromStream(key).CreateScoped(Scope.Androidpublisher); var publisherService = new AndroidPublisherService(new BaseClientService.Initializer { HttpClientInitializer = credentialsPlay }); var request1 = publisherService.Purchases.Subscriptions.Get( "com.highiot.mob", "com.highiot.mob.test_subsription", "nceeeoihojjngafdmfmahbii.AO-J1Ow8yISTj4C6MW4mKgXYp9Tizo7iZ8JP6PgIRenFLHj4xHaAuCxffDL5jaxEzq_t2IopZXXa4_uLyZYBsXMwk_wn3pwMXoL9rNDWJoZV8SCkVsXcAlaMJe0l2Mn_-OhhuHbjPVP8Tn0ruP4WUlxGPyxUjkNv_Q" ); var response1 = request1.Execute(); }
服务账号凭证(HighIoT_key.json)
{ "type": "service_account", "project_id": "robotic-circle-243009", "private_key_id": "cb017791695e97d8b2ab68ae94d940ba07def824", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDPJxCrGu1o1AdD\neiBtuxPS/0wdF4chN5KqK0hR8E6x7qfd30I9zI5k07msD3qEo2iuBWwohIeUCWLh\n5x0Xkkx8ADQqWh9Z0HlWcx8JEFIqeKGy+l7j8mnLtv71xxnUSZdPuE7VQhNt9U2F\ng/uCehcF5rRYKsb9m//uS1dzAFfPepnwgOyAbxL91EUX8TFpfjqonof+pV4N4kTd\nT+U6YcK9FEyQCBUIMW3SJRYQE3lVjxKOVI7osoh3ileMMyFmYhROkuHgL4dMijHa\nXtI6d+8ZkbBtmGy28yYFzMwFKdyb5r9locpcpfXRJnRFRgEHRkGBkvAjdQo/KeNp\nznDsEzKlAgMBAAECggEAMrYJ/xEm+EgbhRnDEYnAFyGXVPHbCzcrCMxytlhhM27M\nmmSatz05yJYKOIRLhmfoat159ktHU2ae1dV5ijkuzxZPruSEEz0VTyP8f4AG1U3V\nq9Zd32iLHKsuLCWy/YSMbaAdcFhuIDdyZFKEghL4SuII2SKTtyb21rOL82Osm2Yj\niiB+04huCKOXvau86284c6GuTtUCRRGPuT85LsV4gQvSLa9gSm9UrMonKktXjdRA\nZenOYtofc4gVjIFozHZwLWleSaM/9jaX0IJ7uct3G1DObqEptCfQnSRQsa1Mtv6e\nXSazGPYMAGW+XOF/yWwuM0zCyI3GyEbc989PI/4IuwKBgQD1Yz3qAeQGYMToLNb7\nUMd0OtWxJFHHa2J97Dwlv73/aGroByAkc4bmYo2ub1YW/JVcyu94IfNR0wHGiV07\ncwFOkYlEYDMWv11VMBeqhHrLmk242jM1ZxhIoNC59RcSBnQHnbvHCe2FugKH7s51\nSHV8EUWR+CkIpZRLNIJBEXv4BwKBgQDYHIMBJ0vYE0O+EvJHR3DQrOQN4xLb2GlI\nFvN1+6N2oox5yfXUlHLi9g138cJnqpayERGE9lZfphSoAtgcgidwJDx7VCkf5C+Q\n8P4wkgL24svZhcJJI2xmnTV8LrG6nU81bUu5dyGTnFeeVPQLcoscVKyII1NbXPBc\nIPbmTAoc8wKBgEl7K2osoMTMK4q/Cq19Ngz3JVCDaL3HyVmd6TEApvuZoBHVOGnR\n8n6A2p52lpgRkQSVfHpD6GIDRs/WCIYp3SVS7YD9Ma9JJMDCwwN74m2fylBlftoq\nAhqVlYtp+jualRpGwJlMvsTBu8pK16ZFSXEalvOsFVWSh8KxeaPUgYP3AoGAT0oe\nspSlWhCvYRR4ebh3ZsiYH5Q5fhmnfwCUsKvzrHo1ChYUMLuKb0URafl0dy56fbiP\ncfYjeJJpr77jZYpHR/izjBgzwnSpEweoa0+W8NgDLLrLrqPliLyTPA2xvaMrxZFl\nIBXaZtsMtpW6uFx9N5bFemljkvjFYzfg/lvVtgsCgYEAqMQ8CEjizn91k8ACK6Fs\nFQkCLjSl5h/lvES0+VZDlWMIwos0e6a7vsTVg0IoJ32hY2a7E6R37MbHP2o6lJiS\njJPzBd5pa803DYl8ehId0/8PAUsMscK6LKPblQW9QzoYk5yEjhU1bFLJQfLmmQsV\neRHZgYsNE/U60DnuZsv4wZg=\n-----END PRIVATE KEY-----\n", "client_email": "highiot-server@robotic-circle-243009.iam.gserviceaccount.com", "client_id": "110565816019675715733", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/highiot-server%40robotic-circle-243009.iam.gserviceaccount.com" }
API返回结果
Name Value ◢ response1 {Google.Apis.AndroidPublisher.v3.Data.SubscriptionPurchase} AcknowledgementState 1 AutoRenewing false AutoResumeTimeMillis null CancelReason 0 ▶ CancelSurveyResult {Google.Apis.AndroidPublisher.v3.Data.SubscriptionCancelSurveyResult} CountryCode “UA” DeveloperPayload “apppayload” ETag “\"kLoaNGFQwzHXpxRSLTfX9req9yE/1xXhq0Lm_lUloQUDN3UhbVIoE08\"” EmailAddress null ExpiryTimeMillis 1568883651389 FamilyName null GivenName null Kind “androidpublisher#subscriptionPurchase” LinkedPurchaseToken null OrderId “GPA.3309-8881-6545-64850” PaymentState 1 PriceAmountMicros 21990000 PriceChange null PriceCurrencyCode “UAH” ProfileId null ProfileName null PurchaseType null StartTimeMillis 1566205275451 UserCancellationTimeMillis 1566209506502
当前配置情况
- Google Play Console:已关联项目,添加了服务账号,服务账号已出现在用户菜单中
- Google API开发者控制台:已为服务账号授权,启用了Google Play Android Developer API,并添加了查看用户信息的权限范围
核心原因与解决办法
为什么这些字段返回null?
Google Play不会默认返回用户的邮箱、姓名等敏感隐私信息,必须同时满足两个条件:
- 你的应用在发起购买时,主动请求获取用户个人信息的授权
- 用户在购买流程中明确同意授权你的应用获取这些信息
具体修复步骤
1. 修改内购代码,触发用户授权流程
你当前使用的是Xamarin的CrossInAppBilling第三方插件,需要确保插件支持请求用户账号信息。尝试在调用PurchaseAsync前添加以下代码(需确认插件版本是否支持该API):
// 请求获取用户账号信息 CrossInAppBilling.Current.SetObtainAccountDetails(true);
如果插件不支持,建议直接切换到官方Google Play Billing Library(Xamarin也有对应的绑定库),官方库提供了完整的AccountIdentifiers获取能力,能确保你正确触发授权流程。
2. 关闭测试模式测试
你代码中设置了CrossInAppBilling.Current.InTestingMode = true;,测试模式下Google Play会模拟购买流程,不会返回真实的用户个人信息。建议切换到内部测试渠道或正式环境,用真实账号完成购买测试。
3. 确认服务账号权限
虽然你已经添加了androidpublisher权限,仍需在Google Play Console的「用户和权限」-「服务账号」中,确认服务账号拥有**「查看订单和订阅数据」**的权限(通常是「订单管理」或「财务数据」相关权限)。
4. 检查用户授权状态
如果用户在购买时拒绝了授权请求,这些字段依然会返回null。你可以在购买成功后,先通过Billing API的AccountIdentifiers获取用户账号信息(如果授权成功),再调用Subscriptions.Get接口,此时个人信息字段才会被填充。
内容的提问来源于stack exchange,提问作者Slava

