Google Sheets API V4 for reading public sheet with less steps - android

We would like to provide a list of reference from a public sheets that everyone can view in android.
I tried the Quickstart sample from Google which works just fine.
But we would like to minimize the steps (steps like allow access to contacts, choosing google account) since this apps is designed for people who's considering suicide. The list is fill of info about where to ask for help.
I did find a article about how to read a sheet as a InputStream
I would really appreciate if there's more elegant way with Google Sheet API V4

If the Sheets are shared to "anyone with link" or "public", it might not be necessary to go through the account flow in Android. Choosing an account is mainly to get access to the right credentials, but public sheets can be read anonymously (without credentials) with the API.

If you are still looking for an answer, only a single line replacement is needed for this to work:
Credential credential = new GoogleCredential().createScoped(SCOPES);
instead of
Credential credential = authorize();
then you can remove the method authorize() and the corresponding variables

I found out there's a setKey method in com.google.api.services.sheets.v4.Sheets. For the third parameter in Builder, as credential, can be null. But will have error "Requests from this Android client application are blocked" if the Key restricted to Android.

Related

Firebase authentification works but I get error when using the Google Text to Speech API

I've set up a small android and firebase app... Authentification works like a charm, and in the firebase console, I can see my user, logged in with the Google account.
Now I am trying to experiment a little with the Text to Speech api, and in doing so, I followed this tutorial:
https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/texttospeech/cloud-client
I managed to make the small java app work, by setting the GOOGLE_APPLICATION_CREDENTIALS Environment variable (I followed this tutorial for this step: https://cloud.google.com/docs/authentication/getting-started), but I am not sure what I need to do to make that code work in the Android app where the users are authentificated..
The Error that I get when trying to make a call to the TextToSpeech API is:
The Application Default Credentials are not available. They are
available if running in Google Compute Engine. Otherwise, the
environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined
pointing to a file defining the credentials. See
https://developers.google.com/accounts/docs/application-default-credentials
for more information.
The error mentioned comes from the line:
TextToSpeechClient textToSpeechClient = TextToSpeechClient.create();
This error appears because of the fact that on the android emulator I don't have access to the credentials that are set as environment variable in my OS..So I have to provide the credentials in another way.
In the case of other Google APIs, like Storage, I found out that this can be done like this:
// You can specify a credential file by providing a path to GoogleCredentials.
// Otherwise credentials are read from the GOOGLE_APPLICATION_CREDENTIALS environment variable.
GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(jsonPath))
.createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();
I managed to create the GoogleCredentials object with the contents of the json file, however the TextToSpeech client doesn't seem to provide a functionality similar to this:
StorageOptions.newBuilder().setCredentials(credentials).build()
So my question is....is there a way to provide the Credentials object to the TextToSpeech client?
Thanks
Currently, there is not a way to provide credentials to the TTS Client from this page.
Due to Security / Auth reasons, I believe the best suggested approach is to use Firebase Functions.
Get the Text
Call Firebase Functions
Have Firebase Functions call the TTS API
Return the results.
This way, no keys are leaked inside the application and you can use Firebase Auth.
Let me know if that helps!
Update:
Option 2: iOS Tutorial (should be adaptable to Android)
Get the Text
Call Firebase Functions
Have Firebase Functions return an OAuth2 Token
Use the token directly with the API

How to get list of downloaded apps (paid/free) by a user from Google Play?

I recently came across this app Purchase Apps, which is somehow able to retrieve apps I've paid for in google play after I signed in using my google account.
I'm trying to find out how it is being done as I want to build a similar app, but for the free apps which were downloaded.
However, I can't find which OAuth API Scope was used for retrieving that information, even after going through the entire list of APIs.
EDIT:
I'm putting a new bounty on this question, as suggested by a similar question I've asked about here, and because here and there I don't see a real answer about how to do it, and what can be done with it.
I'd like to refine the questions into multiple pieces:
What is the API that can be used to get information of purchased apps? Where can I read about it? Please show a full, working example of how to do it.
Can it do more ? Maybe perform search? Maybe show free apps that were installed? Maybe the time they were installed and uninstalled? And the categories of those apps?
Are there any special requirements for using this API ?
EDIT: I'm putting a max bounty on this, because no matter how much I've read and tried, I still failed to make a POC that can query the apps from the Play Store that the user has ever downloaded (name, package name, date installed and/or removed, icon URL, price...), including both paid and free apps.
If anyone finds a working sample, show how it's done, and also show how you've found about it (documentation or anything that has led you to the solution). I can't find it anywhere, and the current solutions here are too vague for me to start from.
Issue is resolved. The exploit has been closed.
We will be closing this bug due to being logged in a Preview version of Android. If the issue is still relevant and reproducible in the latest public release (Android Q), please capture a bugreport and log the bug in https://source.android.com/setup/contribute/report-bugs. If a reply is not received within the next 14 days, this issue will be closed. Thank you for your understanding.
Latest update:
This is a bug and Google will address it in the next update.
We've deferred this issue for consideration in a future release. Thank
you for your time to make Android better
This answer has turned into a conglomeration of ideas and been edited to include information from discussion in the comments.
The androidmarket api, would be a customised api written by the developer. It's not available to the public.
To address your concerns in the comments. The developer would have utilised the current apis available through Android Developer and Google to create a project that manages all of these.
As for accessing Full Account Access, I'm not sure exactly how these developers have achieved this.
I'd recommend using the AccountManager, which is part of android.accounts, has access to credentials and a method getUserData. The account manager has access to passwords and is capable of creating and deleting accounts. This, possibly used with Content Provider
See Udinic/SyncAdapter Authentication.
To reply to your comment:
This blog should help you to get started. Write your own Android Authenticator.
How these apps actually work, I cannot tell you. They may also have different implementations (unless they're a collaborative effort behind the scenes, they most certainly will be different).
One guess. Firstly use GoogleSignInAccount with com.google.android.gms.auth.api.signin.
There a definition for scope, to determine the extent of the permissions the app is granted.
Using requestScopes(), the
public static final String PROFILE
.../ It lets your web app access over-the-air Android app installs.
For example:
GoogleSignInOptions gso =
new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail().
.requestScopes(new Scope("https://www.googleapis.com/auth/contacts.readonly"))
.build();
If full access can be gained a list of all apps used by the account holder can be found and compared to what's on the device.
Package Manager will retrieve a list of all apps currently installed on the device.
PackageInfo provides the details about the app.
INSTALL_REASON_USER will also filter out apps that have been actively installed by the user.
You might want to look at com.google.firebase.appindexing and Log User Actions. Different actions can be tracked.
The users account history is found at https://myactivity.google.com/myactivity.
A helpful link is the OAuth 2.0 Playground.
This github repo node-google-play, using node, is current and will call Google Play APIs. As did the archive that was used as an "unofficial" api, android-market-api, to query the market place.
App 1
The app claims to use the following permissions:
Version 2.1.8 can access:
$ In-app purchases
Other
receive data from Internet
view network connections
full network access
use accounts on the device
prevent device from sleeping
read Google service configuration
Noteworthy, the app doesn't set any permissions when there was a basic, install. I was unable to use any of the features, as I have no paid apps. So for the initial search - there were no permissions needed, which would indicate the app didn't have access to my account.
I checked the permissions - there were none set. So the only thing required was to accept the pop up, as displayed in your question.
App 2
The other app you refer to that does the same thing is more upfront about what is being accessed.
My Paid Apps
SECURITY/PRIVACY NOTICE
The first time you run this app, it will ask for full permission to your Google account. This is unfortunately
the only way to access the required information. No personal
information is stored, no information about your apps is shared with
the developer of this app, nor shared with any third parties.
Everything is kept on your phone only.
I've gone into detail over these apps in this blog post, which was for a university capstone project (no monetary gain). I'm inclined to think this is an exploit in the API and not status by design by Google, as there are no API calls to fetch purchases of apps other than the developer's own app. I hypothesize it's a zero day exploit, in which case there's no legitimate way to access this information.
In case of one of these applications (My Paid Apps), after checking the network traffic it is pretty obvious that it does use the Store's Account page to retrieve the list of paid applications.
Now, the mechanism it uses is the same mechanism that Google Chrome currently, and Pokemon GO supposedly at a point in time used.
In a nutshell, steps to do so are as follow:
Login:
What the mentioned program do for the first step is to log the user in and get access to the user's access token. To do so, it uses the android.accounts.AccountManager.getAuthToken() method. (See more: AccountManager)
However, as for the token scope, oauth2:https://www.google.com/accounts/OAuthLogin is requested.
It might be important to note that based on the OAth2 documentation from Google, this scope is not valid; however, it seems like a valid scope for Google OAuth v1.
Converting the newly retrieved access token to a ubertoken:
Now, what actually ubertoken supposed to do, is unknown and there is no official documentation about it. However, it was seen in the wild to be used by chrome browser to login users.
This is done by requesting the https://accounts.google.com/OAuthLogin?source=ChromiumBrowser&issueuberauth=1 page.
Converting ubertoken to website session:
Later on, using the newly created ubertoken it is possible to get a website session using the https://accounts.google.com/MergeSession API endpoint. After this step, the application is essentially capable of loading all personal pages that you can open using your browser while logged in; except some special pages including Payment settings.
Retrieving the list of paid applications:
Requesting and parsing the https://play.google.com/store/account page.
Following is the application's traffic as captured by 'Packet Capture':
As it is clearly visible in the picture, the end result is identical to what I get when I normally open the store's account page on my PC with Chrome Desktop:
Side note:
It seems none of these endpoints are documented as they are primarily used by Google's own programs and should be considered internal. Therefore I strongly recommend not using them in any program or code that you expect to run for a long time or in a production environment.
Also, there is bad news here for you too, it seems that the Google Play's account page only lists paid applications or special free apps (more especially OEM apps). I will try to find some time and dig deeper into the other application.
Interesting articles:
Pokemon tokens
Exploiting Google Chrome's OAuth2 Tokens
If you have root access, You can access /data/data/com.android.vending/databases/library.db
OnePlus3T:/data/data/com.android.vending/databases
-rw-rw---- 1 u0_a2 u0_a2 229376 2018-12-26 18:01 library.db
This database has all information, which app you have downloaded, which apps you have purchased, and even in which app you have done IAP.
Check ownership table, It has all information.
ownership (account STRING, library_id STRING, backend INTEGER, doc_id STRING, doc_type INTEGER, offer_type INTEGER, document_hash INTEGER, subs_valid_until_time INTEGER, app_certificate_hash STRING, app_refund_pre_delivery_endtime_ms INTEGER, app_refund_post_delivery_window_ms INTEGER, subs_auto_renewing INTEGER, subs_initiation_time INTEGER, subs_trial_until_time INTEGER, inapp_purchase_data STRING, inapp_signature STRING, preordered INTEGER, owned_via_license INTEGER, shared_by_me INTEGER, sharer_gaia_id TEXT, shareability INTEGER, purchase_time INTEGER, PRIMARY KEY (account, library_id, backend, doc_id, doc_type, offer_type))
Dealing with unofficial Google APIs is incredibly complicated territory. It's going to be possible to get this to work, but that's all I'll say. Proceed at your own risk.
The first thing you're going to need to do is get a Google Play auth token. This can be done several ways, but here's how they do it in Purchased Apps:
public static String getAuthToken(Activity activity, String userEmail) {
AccountManager accountManager = AccountManager.get(activity);
Account userAccount = new Account(userEmail, "com.google");
Bundle options = new Bundle();
options.putBoolean("suppressProgressScreen", true);
String token;
try {
Bundle result = accountManager
.getAuthToken(userAccount, "androidmarket", options, activity, null, null)
.getResult();
token = result.getString("authtoken");
} catch (OperationCanceledException e) {
Log.d(TAG, "Login canceled by user");
return null;
} catch (IOException | AuthenticatorException e) {
Log.e(TAG, "Login failed", e);
return null;
}
return token;
}
A few things to note here:
The above code must be run asynchronously. I recommend RxJava, but an AsyncTask will work.
You must supply a email for the account you want to use. I'll leave the details up to you but this is fairly easy using AccountManager.
After you have an auth token, you can now access any Google Play Store endpoint. The main one used by Purchased Apps is https://android.clients.google.com/fdfe/purchaseHistory. Another one you might be interested in is https://android.clients.google.com/fdfe/details?doc=(package name) (from APKfetch code). Here's a page with some more and some analysis. If you make a request to these APIs, you'll need to supply several headers:
Authorization - "GoogleLogin auth=(your auth token)"
User-Agent - "Android-Finsky/6.4.12.C-all%20%5B0%5D%202744941 (api=3,versionCode=80641200,sdk=" + VERSION.SDK_INT + ",isWideScreen=0)";
X-DFE-Device-Id - your device's Google Services Framework ID, obtained from AdvertisingIdClient.
X-DFE-Client-Id - "am-android-google"
Accept-Language - The device's language code, eg "en".
Now, you need to parse the response. Here's where things get tricky. These APIs returns a message encoded as a Protobuf, so it's essentially just binary data unless you have a schema (which of course, only Google has). One way to go about this in theory is to decompile the Google Play Store app and reuse their generated protobuf models with a tool like JADX.
Unfortunately, I've tried this and it doesn't really work. Protobuf model classes are just too complex for a standard decompiler. What you can use is a tool called PBTK. You'll ideally want to run this on the Google Play Store 6.1.12 APK, since that's the last version before they started using ProGuard. Do note that this program has two errors in its script that need to be fixed before running it: changing 'extracto' to 'extractor' in gui.py and removing the assertion statement on line 500 of jar_extract.py.
Now, that should output all of the response classes as .proto files. Create a folder under src/main called proto and drag the entire generated 'com' directory to it. You can delete everything that's not under com/google/android/finsky/protos. Follow instructions online to setup Gradle with the Protobuf Lite plugin.
When you want to parse a response, you can use the ResponseWrapper class, since they all appear to be contained under that.
That's about as far as I can take you. There's a good chance I got some part of this wrong; JADX is your best friend here, because the best way to figure out what an app is doing is by looking at its code. Hope this helps and happy developing!
you can get the package name of all installed apps on device and then get the information of every installed package that you find in the device from google play without any need to get to user account. there is some third party or unofficial apis to get google play apps details as json by getting the app package name. for example: https://42matters.com/
then use the received information for every package to find free ones.
i have two resources for you to consider, but first, in a word, no. there is no api from GOOGLE to let you do what you want, as these metrics arent stored in the phone, they are on the google play store servors, and google has no OFFICIAL api for the play store. you can however glean some info from these two sites:
https://www.quora.com/Is-there-an-API-for-the-Google-Play-Storeenter link description here
https://android.stackexchange.com/questions/162146/how-to-see-all-the-apps-i-have-downloaded-from-google-play-store
and this is enough to see how to accomplish this.
first, a list of what apps have been downloaded by an account is only referencable by the account. and this can be done through the play store. since your app will be installed on that users phone, this dosnt matter... you're in.
second, you will need a 3rd party API built for the GOOGLE PLAY STORE, there are some out there, check the first link.
using the api of your choice, you will send a get request, to the play store, and in return you should receive in most cases a json object to deserialize.
deserialize the object, and you will have your list. which list you get will depend on the endpoint you use, but that should be explained by/in the API itself.
good luck!

Firebase DynamicLinks - Can i see analytics of link created by the new buildShortDynamicLink API?

I'm using the new buildShortDynamicLink API of Firebase (And it's great).
And i see there are two methodes for the ShortDynamicLink result:
Uri shortLink = task.getResult().getShortLink();
Uri flowchartLink = task.getResult().getPreviewLink();
I tried to use both but still the link doesn't apear in the Firebase dashboard.
What is getPreviewLink used for anyway?
Thanks.
Only analytics for links created in the console will show up in the console.
You can still access the analytics for your short links created via the API by using the Firebase Dynamic Links Rest API as described here (https://firebase.google.com/docs/reference/dynamic-links/analytics).
The getPreview returns the url to a visual flowchart that helps illustrate clearly how the link will work in each context. You can use it to debug the link if you want and to visually see how it will behave in different contexts.
Full disclosure: I work for Firebase.
This is expected. Only links created through the dashboard will show up there.
Think about it from this perspective: when your users are creating hundreds or even thousands of links per day, it will quickly make the dashboard completely useless if they all show up there.
At Branch.io (full disclosure: I'm on the Branch team), we take the same approach by default, though we do offer a manual flag you can change on programmatically-generated links to have them show up on the dashboard if desired.

Request public Google+ profile data

I'm searching the PlayServices equivalent of this call:
https://www.googleapis.com/plus/v1/people/<some_user_id>?key=<your_api_key>
The call above is documentation of the call above is here: https://developers.google.com/+/web/api/rest/latest/people/get
However this is a web API call and my keys are restricted to a limited set of IPs. I think it would be a bad idea to put that key in code. Do you think the same?
Just as a side note I would like get the data without "authorization". I mean I authenticate with my key, but I don't want to ask the user. With the HTTP call above this is possible, so what is the Android SDK equivalent? I'm not asking how to do the GoogleApiClient stuff I have this already working. I just want to know the right call of the plus API.
If there is nothing similar do you know how to authenticate myself at the rest service with my packagename and signature?
In summary I just want to know the (first and last) name of the local G+ accounts like in the Google Foto app.
To load a specific Google+ profile in Android use the load method for com.google.android.gms.plus.People.
public abstract PendingResult<People.LoadPeopleResult> load (GoogleApiClient googleApiClient, String... personIds)

Youtube Data API with OAuth2.0 on Android

I'm trying to use the YouTubeData API with OAuth 2.0 authentication on Android, and i'm kind of struggling with it.
I've searched a lot online, but there's not much help for the Android implementation.
First of all, it's not clear to me what's the best way to obtain an OAuth token. In the doc they suggest that for Android is better to obtain it using the Google Play services lib. Is that true? if yes, it should be pretty trivial following this guide: https://developers.google.com/android/guides/http-auth.
But at this point i will have the token in a String object .. how should I use it with the YouTubeData API? Should I place it somewhere in the YouTube.Builder ?
YouTube youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, new HttpRequestInitializer() {
public void initialize(HttpRequest request) throws IOException {
}
}).setApplicationName("AppName").build();
if yes, does anyone know where?
Searching on StackOverflow i've come across this question: What to do after getting Auth Token - Android Youtube API. Here Ibrahim Ulukaya says it's better to use GoogleAccountCredential. For what i've understood (Access to Google API - GoogleAccountCredential.usingOAuth2 vs GoogleAuthUtil.getToken()) the Android version of GoogleAccountCredential should use the GoogleAuthUtil provided from the Google Play services lib, so it could be pretty useful to simplify the process. I've looked at the sample project suggested from Ibrahim Ulukaya (https://github.com/youtube/yt-direct-lite-android) and i've implemented everything as he does. But it doesn't seem to work very well as i'm only obtaining this message in the logcat: "There was an IO error: com.google.android.gms.auth.UserRecoverableAuthException: NeedPermission : null".
(Note that I've enabled all the required APIs on the Google Console, and created the Client ID for my app)
At this point i'm kind of lost.
Should I use directly the GoogleAuthUtil from the Google Play services lib? in this case once obtained the token as a String how can i use it with the YouTubeData APIs?
Or should I use the GoogleAccountCredential ? in this case someone knows how can I solve the "NeedPersmission : null" error?
---- EDIT:
details on what my app is trying to do: being this my first experience with this kind of APIs I started from the easy stuff: retrieve video information and then play those videos, without any user authentication. I managed to do that pretty easily, but for my app's purpose i need to access the user data, in particular users must be able to like and comment videos.
So I started implementing OAuth2, trying to do the same exact queries I was doing before (retrieve video info).
Wow. The documentation on this is super confusing. Full disclosure, I'm not an Android developer but I am a Java developer who has worked with Google apps and OAuth2.
Google Play or not Google Play? First off, Google Play Services will only be available on Android devices with Google Play Services installed (so not OUYA, Amazon devices, etc.). Google state that "the Google Play library will give you the best possible performance and experience.".
There are numerous discussions (e.g. here, here) from actual Android developers that list the various merits of Google Play verses other techniques. I would imagine that once you are able to get your application working using one method, then it should be an easy enough to change if you so desire.
Much of the example code about uses the Android AccountManager (Tasks and Calendars being favourite examples) so that is what I will show.
Your example code looks like it might be for a simple search, I would guess that many of the YouTube API interactions do not require OAuth2, in other code I've seen this empty HttpRequestInitializer implementation referred to as a no-op function. (e.g. GeolocationSearch.java).
It sounds like you want access to YouTube API operations that need account credentials. You can do something similar to this Android Calendar example (CalendarSampleActivity.java) except with YouTube, like the example answer from here.
// Google Accounts
credential = GoogleAccountCredential.usingOAuth2(this, YouTubeScopes.YOUTUBE, YouTubeScopes.YOUTUBE_READONLY);
SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
credential.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));
// YouTube client
service =
new com.google.api.services.youtube.YouTube.Builder(transport, jsonFactory, credential)
.setApplicationName("Google-YouTubeAndroidSample/1.0").build();
I hope this helps.
In the initialize method of the HttpRequestInitializer you can set headers of the request. According to Googles documention for Oath2 for devices https://developers.google.com/identity/protocols/OAuth2ForDevices if you have an access token you should put it in the Authorization: Bearer HTTP header.
YouTube youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, new HttpRequestInitializer() {
public void initialize(HttpRequest request) throws IOException {
request.put("Authorization", "Bearer " + yourAccessTokenString);
}
}).setApplicationName("AppName").build();
Remember the space after the Bearer in the authorization header value

Categories

Resources