验证用户的步骤是否正确';Android应用内订阅?
我正在制作一个不需要用户帐户/登录的应用程序,允许用户购买订阅。我想使用Google Play开发者API来验证用户是否拥有已购买/活动订阅。从所有文档中,我收集了以下步骤 你能回答其中的两个问题吗验证用户的步骤是否正确';Android应用内订阅?,android,service,google-api,google-play,subscription,Android,Service,Google Api,Google Play,Subscription,我正在制作一个不需要用户帐户/登录的应用程序,允许用户购买订阅。我想使用Google Play开发者API来验证用户是否拥有已购买/活动订阅。从所有文档中,我收集了以下步骤 你能回答其中的两个问题吗 在GoogleAPI控制台中创建一个 保存提供给我的私钥(在哪里?当然不是在我的代码中/在设备上) 用于使用私钥创建和签署JWT(如何?但这不是Java代码…我该如何处理它?) 构造一个访问令牌请求,并获得对API的访问权 应用程序现在可以向API发送请求,以确定 用户有一个订阅 当访问令牌到期时,
编辑:这些步骤不正确。有关正确的步骤,请参见下面的答案。但是,请注意,这只适用于使用服务帐户(因为我不想要求用户必须明确允许API访问)我可能误解了你的问题,但我不认为你有理由使用你正在引用的链接来获取安卓应用的应用内计费。此页面更有帮助: 您可以试用它们包含的演示应用程序(地下城--)。它使用产品(一次性购买)而不是订阅,但您应该能够修改以测试所需内容 我认为,对于您来说,关键在于他们在示例中提供的restoreTransactions方法,以查看Google Play帐户是否有您应用程序的订阅:
@Override
public void onRestoreTransactionsResponse(RestoreTransactions request, int responseCode) {
if (responseCode == BillingVars.OK) {
// Update the shared preferences so that we don't perform a RestoreTransactions again.
// This is also where you could save any existing subscriptions/purchases the user may have.
SharedPreferences prefs = getSharedPreferences(my_prefs_file, Context.MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(DB_INITIALIZED, true);
edit.commit();
} else {
Log.e(TAG, "RestoreTransactions error: " + responseCode);
}
}
由于您有一个应用程序可以调用的web服务,我建议您将私钥安全地存储在服务器上。您应该尽可能多地将应用程序内的内容转移到服务呼叫中,请参阅。我已经实现了应用内订阅,但它是在API的这一部分发布之前实现的。我必须自己进行注册和安全验证,但是看起来这个API使用OAuth为您完成了大部分注册和安全验证,尽管看起来您仍然负责存储订阅请求/验证
当它谈到用现有库为JWT签名时,它们确实会为您提供指向java库、Python库和PHP库的链接——这取决于您的web服务或服务器组件是用什么编写的(我的是C#,所以我使用RSACryptoServiceProvider)来验证签名的购买。他们使用JSON对象进行数据的实际传输。事实证明,我的步骤不正确。我花了好几个星期才弄明白这一点,似乎在其他地方都没有记录。不客气:
https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=[您的重定向URI]&客户端id=[您的客户端id]
并在提示时允许访问1/…
在下一步中您将需要此“代码”。刷新令牌永不过期https://accounts.google.com/o/oauth2/token?client_id=[您的客户ID]&CLIENT\u secret=[您的客户机密]&code=[上一步的代码]&grant\u type=authorization\u code&redirect\u uri=[您的重定向uri]
。您可以将结果值保存在程序中;除非明确撤销,否则它永远不会过期。(此步骤由@BrianWhite插入--请参见注释)
确保您正在使用POST。(由Gintas插入)https://accounts.google.com/o/oauth2/token
使用基本名称对“授权类型”、“刷新令牌”
、“客户id”、[您的客户id]
、“客户机密”、[您的客户机密]
、“刷新令牌”、[您的刷新令牌]
。例如,请看。您需要在单独的线程中执行此操作,可能需要使用AsyncTask。这将返回一个JSONObjecthttps://www.googleapis.com/androidpublisher/v1/applications/[您的应用程序包名称]/subscriptions/[您从ANDROID开发者控制台发布的订阅ID]/purchases/[用户购买订阅时收到的购买令牌]?accesstoken=”[步骤4中的访问令牌]“
。查看示例如果你像我一样,想在PHP中实现这一点,下面是如何实现这一点的过程……多亏了卡琳娜的回答,我只用了三天时间就搞定了它的工作原理:) 下面是:
$url ="https://accounts.google.com/o/oauth2/token";
$fields = array(
"client_id"=>"{your client id}",
"client_secret"=>"{your client secret}",
"refresh_token"=>"{your refresh token 1/.....}",
"grant_type"=>"refresh_token"
);
$ch = curl_init($url);
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_POST,count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//execute post
$lResponse_json = curl_exec($ch);
//close connection
curl_close($ch);
"access_token" : "{the access token}", "token_type" : "Bearer", "expires_in" : 3600
$lAccessToken = "{The access token you got in}" ;
$lPackageNameStr = "{your apps package name com.something.something}";
$lURLStr = "https://www.googleapis.com/androidpublisher/v1.1/applications/$lPackageNameStr/subscriptions/$pProductIdStr/purchases/$pReceiptStr";
$curl = curl_init($lURLStr);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$curlheader[0] = "Authorization: Bearer " . $lAccessToken;
curl_setopt($curl, CURLOPT_HTTPHEADER, $curlheader);
$json_response = curl_exec($curl);
curl_close($curl);
$responseObj = json_decode($json_response,true);
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
List<String> scopes = new ArrayList<String>();
scopes.add(AndroidPublisherScopes.ANDROIDPUBLISHER);
Credential credential = new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
.setServiceAccountId(googleServiceAccountId)
.setServiceAccountPrivateKeyFromP12File(new File(googleServicePrivateKeyPath))
.setServiceAccountScopes(scopes).build();
AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential).build();
AndroidPublisher.Purchases purchases = publisher.purchases();
final Get request = purchases.get(packageName, productId, token);
final SubscriptionPurchase purchase = request.execute();
// Do whatever you want with the purchase bean
using System.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Services;
using Google.Apis.Auth.OAuth2;
using Google.Apis.AndroidPublisher.v3;
...
public Task<SubscriptionPurchase> GetSubscriptionPurchase(string packageName, string productId, string purchaseToken)
{
var certificate = new X509Certificate2(
"{{your p12 file name}}",
"{{ your p12 secret }}",
X509KeyStorageFlags.Exportable
);
var credentials = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer("{{ your service account email }}")
{
Scopes = new[] { AndroidPublisherService.Scope.Androidpublisher }
}.FromCertificate(certificate));
var service = new AndroidPublisherService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials,
ApplicationName = "my server app name",
});
return service.Purchases.Subscriptions.Get(packageName, productId, purchaseToken).ExecuteAsync();
}