Currently if I want to promote my Android app from Alpha to Beta, I do it in Google Developer Console.
I am trying to automate this process using the C# client of Google APIs. Is it possible? If so, I'd love to see a code sample.
Thanks!
I will answer myself, based on the answer I got here: https://github.com/googlesamples/android-play-publisher-api/issues/20#issuecomment-107923343
Something like this works for me:
var service = new AndroidPublisherService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential
});
// Insert new edit
var edit = new AppEdit()
{
ExpiryTimeSeconds = ToEpochTime(DateTime.UtcNow.AddMinutes(30)).ToString()
};
edit = service.Edits.Insert(edit, packageName).Execute();
// Fetching the Alpha track and clearing the version code from it
var tracks = service.Edits.Tracks.List(packageName, edit.Id).Execute().Tracks;
var alphaTrack = tracks.Single(track => track.TrackValue.Equals(EditsResource.TestersResource.GetRequest.TrackEnum.Alpha.ToString(), StringComparison.InvariantCultureIgnoreCase));
var versionCode = alphaTrack.VersionCodes.Single();
alphaTrack.VersionCodes.Clear();
service.Edits.Tracks.Patch(alphaTrack, packageName, edit.Id, EditsResource.TracksResource.PatchRequest.TrackEnum.Alpha).Execute();
// Updating a Beta track with the same version code as in the Alpha track
var betaTrack = new Track {TrackValue = "beta", VersionCodes = new [] { versionCode }};
service.Edits.Tracks.Update(betaTrack, packageName, edit.Id, EditsResource.TracksResource.UpdateRequest.TrackEnum.Beta).Execute();
// Commit the edit
service.Edits.Commit(packageName, edit.Id).Execute();
Related
I'm trying to implement Google Sign-in option for my android app using Qt and Firebase Google Authentication by using Connecting your Qt application with Google Services using OAuth 2.0 and Authenticate Using Google Sign-In and C++.
After clicking on a push button in my app the consent page (if I didn't misname it) loads correctly which allows the user to choose his/her desired google account but after that nothing happens. I don't know whether the problem is with my redirected URI or something else.
I have enabled Google Sign-in Option in my Firebase Console and followed the suggested steps in this Question. What am I missing or doing wrong here?
Here is my code:
this->google = new QOAuth2AuthorizationCodeFlow(this);
this->google->setScope("email");
connect(this->google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, &QDesktopServices::openUrl);
QByteArray val;
QFile file;
file.setFileName(QDir::toNativeSeparators(":/client_secret.json"));
if(file.open(QIODevice::ReadOnly | QIODevice::Text))
{
val = file.readAll();
file.close();
}
QJsonDocument document = QJsonDocument::fromJson(val);
QJsonObject object = document.object();
const auto settingsObject = object["web"].toObject();
const QUrl authUri(settingsObject["auth_uri"].toString());
const auto clientId = settingsObject["client_id"].toString();
const QUrl tokenUri(settingsObject["token_uri"].toString());
const auto clientSecret(settingsObject["client_secret"].toString());
//const auto redirectUris = settingsObject["redirect_uris"].toArray();
const QUrl redirectUri("https://MYAPP.firebaseapp.com/__/auth/handler");
const auto port = static_cast<quint16>(redirectUri.port());
this->google->setAuthorizationUrl(authUri);
this->google->setClientIdentifier(clientId);
this->google->setAccessTokenUrl(tokenUri);
this->google->setClientIdentifierSharedKey(clientSecret);
auto replyHandler = new QOAuthHttpServerReplyHandler(port, this);
replyHandler->setProperty("redirect_uri", "https://MYAPP.firebaseapp.com/__/auth/handler");
this->google->setReplyHandler(replyHandler);
this->google->grant();
connect(this->google, &QOAuth2AuthorizationCodeFlow::granted, [=](){
firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(_app);
firebase::auth::Credential credential = firebase::auth::GoogleAuthProvider::GetCredential(google->token().toUtf8(),nullptr);
firebase::Future<firebase::auth::User*> result = auth->SignInWithCredential(credential);
result.OnCompletion([&](const firebase::Future<firebase::auth::User*>& result)
{
if (result.error()==0)
{
qDebug() << "good to go";
}
else
{
qDebug() << result.error_message();
}
}
);
});
We don't use Firebase, but we noticed that the only way to get a response from the OAuth flow is by using http://127.0.0.1:1234/ as the redirect URL. We wrote about authenticating with Google SSO and Qt in our blog, including a discussion of this aspect, and code samples that build on the Qt-provided examples.
I've implemented App-Licensing for InApp-Billing and now I'm getting Error.NOT_LICENSED and I have no idea what's wrong. The version I'm working on has not been published to the play store yet.
This is the code I use to start the licensing-process:
private void checkLicense(int retries) {
if (retries != 5) {
String publicKey = "YOUR KEY";
final CdcLicenseCheckerCallback callback = new CdcLicenseCheckerCallback();
String deviceId = mPrefsHandler.getDeviceId();
deviceId = deviceId != null ? deviceId : UUID.randomUUID().toString();
mPrefsHandler.setDeviceId(deviceId);
Crashlytics.setBool("has Device-Id", deviceId != null);
final LicenseChecker checker = new LicenseChecker(this, new ServerManagedPolicy(this,
new AESObfuscator(new byte[] { 1, 1, ... , 1 }, getPackageName(),
deviceId)), publicKey);
checker.checkAccess(callback);
}
}
I used a production variant to figure out what's happening and found that in LicenseValidator.java, the parameter signature for the method verify is an empty string, causing the sig.verify(Base64.decode(signature)) to return ERROR.NOT_LICENSED.
if (!sig.verify(Base64.decode(signature))) {
Log.e(TAG, "Signature verification failed.");
handleInvalidResponse();
return;
}
I only have a hint of an idea that UUID.randomUUID().toString() might be the issue, but I have no idea, whether it actually, nor what to do here.
Found the problem. I hadn't actually published the alpha-version to the playstore, so google play explicitly disallowed the newer version, because it didn't know about it
Solution: Check, if your installed app version is lower or equal to the latest version that was published to google play (alpha, beta or production channel)
My desktop app used www.google.com/accounts/ClientLogin (which currently unavailable) to obtain authentification token, that i used to get android application info from unofficial market api (https://androidquery.appspot.com/api/market?app=(put the package name here))
Now Google want me to use OAuth authorization because ClientLogin deprecated and response 404 all time.
So question is - how can i get android application info by "appId" (just version code for example - "23") using OAuth 2.0 and Google Client Api Libraries for .NET?
And another question - how i can manually generate this request
POST "https://accounts.google.com/o/oauth2/token HTTP/1.1"
User-Agent: google-api-dotnet-client/1.9.3.19379 (gzip)
Content-Type: application/x-www-form-urlencoded
Host: accounts.google.com
Content-Length: 750
Connection: Keep-Alive
assertion=?
I can see in Fiddler how this request send from google lib? but it stores the response inside lib and i can't access to auth token:
{
"access_token" : "TOKEN_HERE",
"token_type" : "Bearer",
"expires_in" : 3600
}
???
I found solution for this problem.
Google Api provides one method to obtain apllication version code.
Firstly, you need to create a project in Google Developers Console, create credentials for Service Account with p12 key file.
And enable Google Play Developers Api.
In Google Play Developers Console you should link your app to this project.
After, you can write this code in eour desktop .NET appliation:
var serviceAccountEmail = "YOUR Service Account Email";
var certificate = new X509Certificate2(#"key.p12", "YOUR_CLIENT_SECRET", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { AndroidPublisherService.Scope.Androidpublisher }
}.FromCertificate(certificate));
var service = new AndroidPublisherService(
new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Edits Sample"
});
var apiEditBody = new AppEdit();
// packageName - your app id like com.myapp.test
var appEdit = service.Edits.Insert(apiEditBody, packageName)
.Execute();
var list = service.Edits.Apks.List(packageName, appEdit.Id)
.Execute()
.Apks;
var deletingEditResult = service.Edits.Delete(packageName, appEdit.Id).Execute();
var versionCode = list.Last().VersionCode.Value;
That's it.
Hope, this answer will help somebody =)
Similar to solution above which was very helpful to me, here is a solution that gets the latest production track version code of your app using the Google API's:
var path = "PATH_TO_JSON_KEY";
var credential = GoogleCredential.FromFile(path).CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var service = new AndroidPublisherService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = "Production Version Checker" });
var appEdit = service.Edits.Insert(new AppEdit(), "com.package.name").Execute();
var listTracks = service.Edits.Tracks.List("com.package.name", appEdit.Id).Execute();
var productionTrack = listTracks.Tracks.FirstOrDefault(t => t.TrackValue == "production");
var latestProductionRelease = productionTrack.Releases.FirstOrDefault(r => r.Status == "completed");
var latestProductionVersionCode = latestProductionRelease.VersionCodes.FirstOrDefault();
var deletingEditResult = service.Edits.Delete("com.package.name", appEdit.Id).Execute();
I am using Xamarin Forms and want to integrate Facebook in android app. I want to pull the feed from a page like https://www.facebook.com/HyundaiIndia
I have installed Xamarin.Facebook from Nuget. It doesn't have a FacebookClient object as mentioned in here: https://components.xamarin.com/gettingstarted/facebook-sdk
Then I found the Xamarin.Facebook and Xamarin.FacebookBolts namespaces which I included, but I still didn't get FacebookClient. Instead I found Xamarin.Facebook.XAndroid.Facebook and I created an instance:
Xamarin.Facebook.XAndroid.Facebook fb = new Xamarin.Facebook.XAndroid.Facebook(FacebookAppId);
But this object doesn't have GetTaskAsync. How do I pull down the feeds in Xamarin?
I had the same experience trying following the article you mentioned.
The component created by Outercurve Foundation (Facebook.dll version 6.2.1)
needs that you reference Facebook.dll and you include it in your file like this:
using Facebook;
Don't confuse it with:
using Xamarin.Facebook;
EDIT
I finally found a bit of time for a more complete answer and since the example on the link
doesn't specify how to obtain the AccessToken (called userToken in the facebook-sdk component page example linked in the question) I'm posting one of the possible solutions.
This one works for me and doesn't require any other library or component (but the one already mentioned in the question).
using Xamarin.Auth;
using Facebook;
string FaceBookAppId = "YOUR_FACEBOOK_APP_ID";
string AccessToken;
string OauthTokenSecret;
string OauthConsumerKey;
string OauthConsumerSecret;
void GetFBTokens()
{
var auth = new OAuth2Authenticator(FaceBookAppId,
"",
new Uri("https://m.facebook.com/dialog/oauth/"),
new Uri("https://www.facebook.com/connect/login_success.html")
);
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
eventArgs.Account.Properties.TryGetValue("access_token", out AccessToken);
eventArgs.Account.Properties.TryGetValue("oauth_token_secret", out OauthTokenSecret);
eventArgs.Account.Properties.TryGetValue("oauth_consumer_key", out OauthConsumerKey);
eventArgs.Account.Properties.TryGetValue("oauth_consumer_secret", out OauthConsumerSecret);
}
};
}
//Now we can use the example of the link.
void PostToMyWall ()
{
FacebookClient fb = new FacebookClient (AccessToken);
string myMessage = "Hello from Xamarin";
fb.PostTaskAsync ("me/feed", new { message = myMessage }).ContinueWith (t => {
if (!t.IsFaulted) {
string message = "Great, your message has been posted to you wall!";
Console.WriteLine (message);
}
});
}
There are 2 editions of Facebook SDK, one is binding for official SDK, another is from Outercurve Foundation.
Looks like you're using this one: the "official" binding , so check the documentation on this link.
I'm trying to access a Purchase Status API from my ASP.NET web server using Google APIs .NET Client Library which is a recommended way for using Purchase API v1.1. However, the Authorization page of this API suggests direct web requests to Google's OAuth2 pages instead of using the corresponding client libraries.
OK, I tried both methods with all variations I could imagine and both of them lead to "The remote server returned an error: (400) Bad Request.".
Now what I've done to get to my point. First I've made all steps 1-8 under the Creating an APIs Console project of the Authorization page. Next I generated a refresh token as described there. During refresh token generation I chose the same Google account as I used to publish my Android application (which is in published beta state now).
Next I've created a console C# application for test purposes in Visual Studio (may be console app is the problem?)
and tried to call the Purchase API using this code (found in some Google API examples):
private static void Main(string[] args)
{
var provider =
new WebServerClient(GoogleAuthenticationServer.Description)
{
ClientIdentifier = "91....751.apps.googleusercontent.com",
ClientSecret = "wRT0Kf_b....ow"
};
var auth = new OAuth2Authenticator<WebServerClient>(
provider, GetAuthorization);
var service = new AndroidPublisherService(
new BaseClientService.Initializer()
{
Authenticator = auth,
ApplicationName = APP_NAME
});
var request = service.Inapppurchases.Get(
PACKAGE_NAME, PRODUCT_ID, PURCHASE_TOKEN);
var purchaseState = request.Execute();
Console.WriteLine(JsonConvert.SerializeObject(purchaseState));
}
private static IAuthorizationState GetAuthorization(WebServerClient client)
{
IAuthorizationState state =
new AuthorizationState(
new[] {"https://www.googleapis.com/auth/androidpublisher"})
{
RefreshToken = "4/lWX1B3nU0_Ya....gAI"
};
// below is my redirect URI which I used to get a refresh token
// I tried with and without this statement
state.Callback = new Uri("https://XXXXX.com/oauth2callback/");
client.RefreshToken(state); // <-- Here we have (400) Bad request
return state;
}
Then I tried this code to get the access token (I found it here: Google Calendar API - Bad Request (400) Trying To Swap Code For Access Token):
public static string GetAccessToken()
{
var request = WebRequest.Create(
"https://accounts.google.com/o/oauth2/token");
request.Method = "POST";
var postData =
string.Format(
#"code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code",
// refresh token I got from browser
// also tried with Url encoded value
// 4%2FlWX1B3nU0_Yax....gAI
"4/lWX1B3nU0_Yax....gAI",
// ClientID from Google APIs Console
"919....1.apps.googleusercontent.com",
// Client secret from Google APIs Console
"wRT0Kf_bE....w",
// redirect URI from Google APIs Console
// also tried Url encoded value
// https%3A%2F%2FXXXXX.com%2Foauth2callback%2F
"https://XXXXX.com/oauth2callback/");
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
using (var dataStream = request.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
}
try
{
// request.GetResponse() --> (400) Bad request again!
using (var response = request.GetResponse())
{
using (var dataStream = response.GetResponseStream())
{
using (var reader = new StreamReader(dataStream))
{
var responseFromServer = reader.ReadToEnd();
var jsonResponse = JsonConvert.DeserializeObject<OAuth2Response>(responseFromServer);
return jsonResponse.access_token;
}
}
}
}
catch (Exception ex) { var x = ex; }
return null;
}
So, to sum up all my long story:
Is it possible at all to pass OAuth2 authorization using either of methods above from a C# Console Application (without user interaction)?
I've double checked the redirect URI (since I saw a lot of discussed troubles because of it here on stackoverflow) and other parameters like ClientID and ClientSecret. What else I could do wrong in the code above?
Do I need to URL encode a slash in the refresh token (I saw that the first method using client library does it)?
What is the recommended way of achieving my final goal (Purchase API access from ASP.NET web server)?
I'll try to answer your last question. If you access your own data account, you dont need to use client id in oAuth2. Let's use service account to access Google Play API.
Create a service account in Google Developer Console > Your project > APIs and auth > Credentials > Create a new key. You will download a p12 key.
Create a C# project. You can choose console application.
Install google play api library from Google.Apis.androidpublisher. Nuget. You can find other library for dotnet in Google APIs Client Library for .NET
Link google api project with your google play account in API access
Authenticate and try to query information. I'll try with listing all inapp item. You can just change to get purchase's status
String serviceAccountEmail = "your-mail-in-developer-console#developer.gserviceaccount.com";
var certificate = new X509Certificate2(#"physical-path-to-your-key\key.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { "https://www.googleapis.com/auth/androidpublisher" }
}.FromCertificate(certificate));
var service = new AndroidPublisherService(
new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "GooglePlay API Sample",
});
// try catch this function because if you input wrong params ( wrong token) google will return error.
var request = service.Inappproducts.List("your-package-name");
var purchaseState = request.Execute();
// var request = service.Purchases.Products.Get(
//"your-package-name", "your-inapp-item-id", "purchase-token"); get purchase'status
Console.WriteLine(JsonConvert.SerializeObject(purchaseState));
You should do the following in your
private static IAuthorizationState GetAuthorization(WebServerClient client) method:
private IAuthorizationState GetAuthorization(WebServerClient client)
{
IAuthorizationState state = AuthState;
if (state != null)
{
return state;
}
state = new AuthorizationState()
{
RefreshToken = "4/lWX1B3nU0_Ya....gAI",
Callback = new Uri(#"https://XXXXX.com/oauth2callback/")
};
client.RefreshToken(state);
// Store and return the credentials.
HttpContext.Current.Session["AUTH_STATE"] = _state = state;
return state;
}
Let me know if it works for you.
Be aware that we know that the whole OAuth2 flow is awkward today, and we are working to improve it.