Background
In the recent months, Google has published a new Analytics alternative, called "Firebase Analytics" .
The problem
As the app already does have Google-Analytics, I find some obstacles that I can't see how to best handle.
The questions
Previously, "newTracker" function needed a property-id. Now I don't see it. Does it mean it doesn't need one?
Previously, "enableAdvertisingIdCollection " was available to collect ads info too. I can't find it in new APIs. Is it automatically collected?
"setDryRun" was available to disable sending the data to the servers, and now I don't see it. Does it mean it's automatically this way for debug versions of the app? Do all functions write to the logs?
Previously, I could track a "screen" :
public void setScreenName(String name) {
mGoogleAnalyticsTracker.setScreenName(name);
mGoogleAnalyticsTracker.send(new HitBuilders.ScreenViewBuilder().build());
}
Now I don't see it, but as I've read, I think it's automatic, so it sends data of the activity lifecycle anyway. Is it true?
Probably the most important thing: previously I could track using category, action, label and value:
public void trackEvent(final String category, final String action, final String label, final long value) {
mGoogleAnalyticsTracker.send(new HitBuilders.EventBuilder()
.setCategory(category).setAction(action)
.setLabel(label).setValue(value).build());
}
and now I see a completely different way to track events ("custom events"), using bundles. Example:
Bundle bundle = new Bundle();
bundle.putString(FirebaseAnalytics.Param.ITEM_ID, id);
bundle.putString(FirebaseAnalytics.Param.ITEM_NAME, name);
bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, "image");
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_CONTENT, bundle);
How does it work? How is it shown in the website of Firebase Analytics? I suppose I could have the first parameter of logEvent behave like the category parameter of the Google-Analytics, but what can/should I do for the rest? According to the docs, this should be ok:
public void trackEvent(final String category, final String action, final String label, final long value) {
Bundle bundle = new Bundle();
bundle.putString("action", action);
bundle.putString("label", label);
bundle.putLong("value", value);
mFirebaseAnalytics.logEvent(category, bundle);
}
Which events are actually automatically being tracked (I ask this because some are said that I shouldn't use, here) ? Do they include purchases? app-invites? ads? Where do I see them in the console website ?
About logs, it says that the new SDK does it by :
You can enable verbose logging with a series of adb commands:
adb shell setprop log.tag.FA VERBOSE
adb shell setprop log.tag.FA-SVC VERBOSE
adb logcat -v time -s FA FA-SVC
What do those commands do? How can I disable it? I've noticed it even gets shown in release version of the app...
Is the new SDK supposed to replace Google-Analytics? Is it suggested to fully move to it? Will Google-Analytics have any updates?
Lots of questions bundled together so I'll try to briefly answer most of them:
Google Analytics reports on tracker-ids, Firebase Analytics reports on applications. There is only one id in the application defined in your google-services.json. The ID is translated to a string resource by google services plugin under "google_app_id" name. All events from the app are reported to this single id.
Firebase Analytics reports AdId automatically. You don't need to enable it.
There is no dryRun feature. You can either use separate google-services.json during development, filter out development version using the app version or add user-property to mark the app instances used for development.
You can report screens with
Bundle params = new Bundle();
params.putString(FirebaseAnalytics.Param.ITEM_CATEGORY, "screen");
params.putString(FirebaseAnalytics.Param.ITEM_NAME, "screen name");
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.VIEW_ITEM, params);
You can log custom event with the same params
Bundle params = new Bundle();
params.putString("category", category);
params.putString("action", action);
params.putString("label", label);
params.putLong("value", value);
firebaseAnalytics.logEvent("xyz_event", params);
The "ga_" prefix is reserved and your analytics will fail if you use it. Instead, use "xyz_" where xyz is your company's initials, for example.
Do not use the category as event name unless you have very few categories you want to track. Firebase Analytics supports up to 500 event names. Logging more than that will cause some of your data to be ignored.
There is a list of reserved event names in the beginning of the FirebaseAnalytics.Event class. It roughly represents the automatic events reported.
Firebase Analytics has debug logging disabled by default. It only logs errors and warnings. If you don't enable debug logging and your app is correctly configured there are only 2 lines that are being logged when the app starts with instructions on how to enable debug logging. There is nothing to disable in production and there is no equivalent to setLogLevel(ERROR) from Google Analytics. WARN is the default logging level. You can only enable logging on individual device by running the adb command on the device). That helps you avoid shipping app in production with debug logging enabled.
Google Analytics SDK for Android and iOS is not deprecated and will be supported and updated for foreseeable future. You don't need to move away from it if you already invested using it in your app and it is meeting your needs.
Google Analytics is a freemium web analytics service offered by Google that tracks and reports website traffic.1 Google launched the service in November 2005 after acquiring Urchin.
Firebase is a cloud services provider and backend as a service company based in San Francisco, California. The company makes a number of products for software developers building mobile or web applications.
How to move from google analytics to firebase analytics?
Google Analytics (GA) and Firebase Analytics (FA), despite their common name, are widely different in many aspects.
While GA is a general-purpose (and more web oriented) analytics tool, Firebase was built keeping mobile in mind: therefore, the feature set is different between the two, with some things that were added in FA and things that are missing from GA.
More specifically, these are some noteworthy points when considering Firebase Analytics:
Real-time view is missing
Events are available after a 4-6 hours period
Behavior Flow (from GA) is missing
The Audiences feature a big advantage of FA and, coupled with Notifications, allows you to engage with a specific group of users
When using Firebase Crash Reporting, an audience with users who experienced a crash is automatically created
Funnel analysis makes much more sense than in GA, since FA is based on events and not on screen views
Free and unlimited, except for the number of types of events (limited to 500); no limits on the volume of events per each type
Some events are logged automatically (i.e., sessions based on Activity lifecycle)
Relatively low methods footprint, compared to GA's methods count
Dead-easy to setup, there is no singleton to initialize, just include the Gradle dependency and start logging events
All-in-one console, if you plan on using other Firebase services
As to if one should consider switching from one to the other, or if to keep both in parallel, the answer is: it depends.
If you were using GA extensively before, chances are that you would be missing some of its feature when switching completely to FA.
However, if this is a fresh start for your project, FA is much more prone to a cross-platform mobile-oriented environment, so you may very well consider it as your own analytics tool.
On a side note, keep in mind that Firebase has just launched and Google has plans on adding more features in the coming weeks (e.g., real-time dashboard).
For tutorial you can find here https://firebase.google.com/docs/analytics/android/start/
Related
At work we are trying to use the optional campaign tracking UTM arguments when creating dynamic links through the firebase portal.
The dynamic links are working fine, and as far as I can tell from all the official documentation, just adding the UTM values in the final optional step when creating dynamic links should cause those values to be sent along with the dynamic_link_app_open event.
However, we are not seeing any attribution values when we look on the events OR conversions tabs for the dynamic_link_app_open event. We see that event is being sent but we just don't get the campaign attribution values so we have no idea what campaigns led to those events and conversions.
The documentation is really lacking on this particular feature and it's frustrating our marketing department which is ultimately ending up with the developers (i.e. me).
I have developed a work around, but it's a hack:
When creating the dynamic link on the firebase portal, I put utm_source, utm_medium and utm_campaign query strings directly into the deep link like so (not our actual deep link for security reasons, but you get the idea):
https://www.example.com?utm_source=Test&utm_medium=Test&utm_campaign=Test
Then in the client, I have added code to rip these out of the resulting deep link after passing the dynamic link through the firebase dynamic links SDK. With these 3 bits of information I can send an app_open event to firebase analytics via the FirebaseAnalytics SDK like so:
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent())
.addOnSuccessListener(this, pendingDynamicLinkData -> {
if (pendingDynamicLinkData != null) {
Uri optionalDynamicDeepLink = pendingDynamicLinkData.getLink();
if (optionalDynamicDeepLink != null) {
List<String> utmSource = optionalDynamicDeepLink.getQueryParameters(UTM_SOURCE);
List<String> utmCampaign = optionalDynamicDeepLink.getQueryParameters(UTM_CAMPAIGN);
List<String> utmMedium = optionalDynamicDeepLink.getQueryParameters(UTM_MEDIUM);
if (!utmSource.isEmpty() && !utmCampaign.isEmpty() && !utmMedium.isEmpty()) {
String utmSourceParam = String.valueOf(utmSource);
String utmCampaignParam = String.valueOf(utmCampaign);
String utmMediumParam = String.valueOf(utmMedium);
Bundle params = new Bundle();
params.putString(FirebaseAnalytics.Param.SOURCE, utmSourceParam);
params.putString(FirebaseAnalytics.Param.CAMPAIGN, utmCampaignParam);
params.putString(FirebaseAnalytics.Param.MEDIUM, utmMediumParam);
FirebaseAnalytics.getInstance(this).logEvent(FirebaseAnalytics.Event.CAMPAIGN_DETAILS, params);
FirebaseAnalytics.getInstance(this).logEvent(FirebaseAnalytics.Event.APP_OPEN, params);
}
String dynamicDeepLink = optionalDynamicDeepLink.toString();
if (!handleDeepLink(dynamicDeepLink)) {
Generic.openLinkInCustomTabs(getApplicationContext(), deepLinkOptional);
}
} else {
if (!handleDeepLink(deepLinkOptional)) {
handleIntent(intent);
}
}
} else {
if (!handleDeepLink(deepLinkOptional)) {
handleIntent(intent);
}
}
}).addOnFailureListener(this, e -> {
if (!handleDeepLink(deepLinkOptional)) {
Generic.openLinkInCustomTabs(getApplicationContext(), deepLinkOptional);
}
});
Whilst this works, it begs the question; what is the point of the optional campaign tracking section when creating dynamic links? Presumably putting the utm_source, utm_medium and utm_campaign there is supposed to allow firebase to auto-magically populate the dynamic_link_app_open event with said campaign tracking data, but it doesn't.
For instance, here is how I've setup that optional final step:
I have then followed the dynamic link into the app several times as well as asking testers to do the same. I have waited over 36 hours (as I'm aware these events can take some time to propagate to the cloud) and we're seeing dynamic_link_app_open events build up, indicating an event is logged for our dynamic links, but when we drill into that event there is no UTM information collected.
Is this feature of firebase broken?
I can see this from official firebase documentation (https://firebase.google.com/docs/dynamic-links/analytics):
Which indicates that collection of UTM data from dynamic link clickthroughs is not supported on firebase, but is supported on google analytics. This isn't confusing at all (/sarcasm).
So presumably some of our data (i.e. the bit to do with campaign tracking) is collected/hosted by google analytics?
To add further confusion, the official documentation for firebase dynamic links states:
"If you mark Dynamic Link events as conversions, you can see how your Dynamic Links are performing on the Attribution page."
And then shows an image of the firebase portal UI which doesn't even match to reality:
I've searched and searched for an attribution tab on the firebase console but there isn't one... these docs are enough to drive a developer insane.
I reached out to Google, as the Issue still does not seem to be solved. Here is the answer:
"Currently, Firebase Dynamic Links UTM event tracking for iOS platforms is not supported due to the fingerprint matching mechanism for iOS platform limitation. As an action, I’ve linked this support ticket to our existing feature request to let our engineering team know of the increasing interest to have this utm_ tracking mechanism implemented for the iOS platform for FDL. I can’t share definite details or timeline for the release, but we are taking your interest moving forward to have this feature improvements. You can check our release notes for any updates."
I don't understand what "the fingerprint matching mechanism" exactly means. But I understand that it will take years until this Issue gets fixed.
I can understand your frustration, we are in the same problem for months now. I also think it should not be the way it works that you need to manually pick up the UTM Parameters. And I did find an older screenshot (from 2019) that showed that Dynamic Links SHOULD do this on their own:
[
This first part still works, but the Source/Medium/Campaign never make it into the Acquisition/Attribution reports. They DID do that in the past:
(example in screenshot is another Dynamic Link than in the first screenshot, sorry)
In talks with Google, it sounded as if they were indeed aware of this as a bug, but offered no specifics on whether or when this would be fixed.
So I can only confirm that you are not alone with your problem...
2021 updated answer:
I guess the problem is fixed and now you can see the events of the dynamic link from the DebugView with all the params (as #Lukas Oldenburg said)
According to this answer:
UTM parameters that you choose in UI are parameters for mobile
tracking. If you want to pass UTM parameters to your "fallback"
website, you need to add them to the fallback address itself.
If I install the app when clicking the dynamic link. All of that information from dynamic should be still available when I open the app for the first time.How can I get that information? It is not working when I use this: getInitialLink() returns Promise<string|null>;
Since, you haven't mentioned - I'm assuming you are having problems with shorter urls, if that's the case try putting the longer url.
Or refer here on Simon's answer: When I use the long instead of short links, everything works perfectly fine.
On Android, you use the getInvitation() method to get data from the Dynamic Link:
AppInvite.AppInviteApi.getInvitation(mGoogleApiClient, this, false).setResultCallback
(/* ... */);
Then, in the callback, you can get the data passed in the Dynamic Links link parameter by calling the getDeepLink() method:
Firebase Documentation - Use Case
For future reference or detailed answer on Firebase Dynamic Links
Behave just like normal Links
In cases where the application doesn’t require installation (say, if it’s already installed) then clicking the Dynamic Link will automatically open the link to the desired screen.
Dynamic Links have a very simple process flow:
The user begins by clicking the Dynamic Link
If the the needs of the Dynamic Link target are satisfied (this is, the application being installed) then the user is navigated to the target location
Otherwise, if the application requires install in order to navigate
to the Dynamic Link target, the the user is taken to the point of
install for the application. Once the application has been installed,
the user is navigated to the target location of the Dynamic Link
And if that wasn’t all, we can integrate Dynamic Links with Firebase Analytics to track the interaction with any links that we generate for our applications. But if we only require simple tracking, then we can use the automatic built-in analytics from the Dynamic Links panel within the Firebase Console where we can also obtain attribution and referrer information for interacted links with no extra effort required from our side.
What makes it different from Google Analytics?
One of the first things that came to my mind when I read about Firebase Analytics was, “What about my Google Analytics setup?”. So if you already have Google Analytics in place, then why would you make the switch to Firebase Analytics? Well, here’s a couple of differences between the two:
Audiences
We can use Firebase Analytics to create Audiences — these are groups of users that we can then interact with using other Firebase service such as Firebase Notifications and / or Firebase Remote Config.
Integration with other Firebase Services
An awesome thing with Firebase Analytics is that we can integrate other Firebase services with analytics. For example, creating an Audience of users who have experienced a crash reported through Firebase Crash Reporting.
Lower Method Count
The Google Analytics dependency on Android has a total count of 18,607 methods and has a total of 4kb used for dependancies. On the other hand, Firebase Core (for Analytics) has a method count of 15,130 and only 1kb used for dependancies.
Automatic Tracking
When we add the firebase core dependency, it will automatically begin tracking a collection of user engagement events and device information for us — this is useful if you’re looking to only collect the minimal data for your app.
Unlimited Reporting
For up to 500 events, Firebase Analytics provides us with unlimited reporting straight out of the box for free!
No Singleton Initialisation
When setting up Google Analytics on Android we are required to initialize a Singleton instance. Firebase Analytics are simply available by fetching the instance directly from where we wish to track data. This isn’t much effort obviously but just makes the setup flow slightly easier.
Single Console
All of the data for every Firebase service is available for a single console. That makes it both easier and quicker for us to navigate from checking the analytic stats for our app to viewing the latest crash reports.
It looks like this is a react-native-firebase open bug for android
For fix the only thing that is required to be changed in module code:
private boolean isInvitation(PendingDynamicLinkData pendingDynamicLinkData) {
return FirebaseAppInvite.getInvitation(pendingDynamicLinkData) != null;
}
to
private boolean isInvitation(PendingDynamicLinkData pendingDynamicLinkData) {
FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(pendingDynamicLinkData);
if (invite != null && invite.getInvitationId() != null && !invite.getInvitationId().isEmpty()) {
return true;
}
return false;
}
Bug reference : https://github.com/invertase/react-native-firebase/issues/1273
Please Check Your Manifest file
open AndroidManifest.file => In your activity tag there is intent-filter tag put below line in that tag.
<data android:scheme="https" android:host="your.dynamic.link" />
<data android:scheme="http" android:host="your.dynamic.link" />
If already done then check this link for the full blog on the dynamic link with react native.
Link: http://blog.logicwind.com/react-native-dynamic-links-using-firebase/
I hope this will help. sorry for the typos.
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!
SITUATION
I have a set of functionalities in my app which changes based on the store it is installed from. E.g. I want to have a more restricted set of advertisements displayed for family audiences and children to be eligible for the Google Play for Education category. In other stores i still want to restrict but don't want to be as stringent as I will be in filtering out the ads.
General observation at my end is that if I opt-in for "Google Play for Education" category it takes a few more hours to get published because of the following (as stated on the developer console):
Checking this box submits this app for inclusion in the "educator
recommended" section of Google Play for Education. The final decision
on which apps to recommend is made by a 3rd party network of teachers.
If your app is selected, we will notify you by e-mail. If not, your
app will still be searchable in Google Play for Education.
Now before the app gets published in this category the network of teachers, I assume, download and test/verify if the guidelines are met and there are no violations.
PROBLEM
To differentiate between the store installed from I'm obviously using this:
PackageManager packageManager = context.getPackageManager();
String installer = packageManager.getInstallerPackageName(packageName);
if (installer == null) installer = ""; //to avoid NPE
if (installer.equals("com.android.vending")) {
//It is installed from Google Play store
//PROBLEM: THIS DOES NOT SEEM TO BE THE PACKAGE NAME RETURNED
//WHEN GOOGLE PLAY REVIEWERS/TESTERS ARE USING THE APP
}
else ...
....
....
//similarly handling other stores here
....
....
....
//After that also checking by installed app stores
....
....
What is happening: After being published things app properly identifies that it is downloaded from play store i.e. it gets com.android.vending as the installerPackageName. But, when it is being reviewed or tested by the network of teachers it appears to be getting a different installerPackageName. This is causing the app to think it has been downloaded from an app store other than Google Play Store. And because of this my app is rejected from the Education category. I need to know this installer package name to handle the scenario correctly.
How do i know this: I have a dedicated ad unit id to use when the detected app store is Google Play and all requests post successful publication (i.e. from the regular play store users) come to this google dedicated ad unit id. But, in the short span of time after submitting the app/update and before the app or and update is published, a few requests come to the non-google ad unit ids, causing the app to fail adherence to the guidelines to be eligible for "Google Play for Education" category. Because, the level of ad filtering in the non-google ad unit ids is slightly less. Hence the teachers evaluating/testing the app see some ads that they think are not as per guidelines and reject it.
Also, here is an article to support the fact that the app gets reviewed manually as well as by automated script before it is actually published to the store.
Current fix or limitation: I've disabled all other ad networks and have to use only admob. The setting of filters even at the strictest level in other ad networks doesn't seem to filter all ads that Google reviewers think are not suitable for children and family audiences. When using only admob the process is smooth and I always qualify.
What I'm looking for to overcome this problem: If i get to know the installerPackageName that is returned when the app is installed from where ever the reviewing network of teachers install the app from, I can handle that case exactly as i handle when i get com.android.vending and everything will be just fine.
I could not find any documentation or reference to obtain this information.
Also, if there is any other way i can identify it the app is in pending publication stage, I force all requests to go to the google ad unit id.
ASSUMPTION: There is a separate installer app for the reviewers and testers (automated/manual what ever it may be in the background) whose installerPackageName is NOT com.android.vending. If there is some Google guy around and can help confirm this (if allowed by Google), do comment. :-)
Other possibilities which i do not want to go with
Disable all other networks manually while the app is in pending publication phase and re-enable them once published. But, I don't want to do this because this would be like bluffing google and I don't want to go that way. I want my app logic to take care of it so that the same thing that is reviewed is let out in market.
I permanently stick with only admob. But this would be foolish as there are no such restrictions in other stores that I'm publishing my apps to and I will terribly lose on fill rate.
I there anyone who has had this issue before OR knows the installerPackageName for the review's download place OR knows how to determine if the app is currently in 'pending publication` state on playstore?
I can also possibly filter all by packagenames starting with com.android or com.google, but I want to keep that as last option. Also, would like to know if the installerPackage name is not set at all in case of those users. In that case I'll need to look at a completely different situation to handle the situation.
I find one thing that can help you in this case. It's analytics. Just create your custom event eg. INSTALLER_STRING in some of analytics systems and log that event when appropriate. Here is the example of event logging in Fabric Answers.
public static final String EVENT_OPEN_TOP_TRENDS = "EVENT_OPEN_TOP_TRENDS";
public static final String TOP_TRENDS_TYPE = "TOP_TRENDS_TYPE";
public static final String TYPE_TOP_TRENDS_IMAGES = "TYPE_TOP_TRENDS_IMAGES";
public static void logEvent(String eventId, String attributeName, String name) {
Answers.getInstance().logCustom(new CustomEvent(eventId).putCustomAttribute(attributeName, name));
}
logEvent(EVENT_OPEN_TOP_TRENDS, TOP_TRENDS_TYPE, TYPE_TOP_TRENDS_IMAGES);
Later on, you can see what are the sources your app was installer from on fabric website.
Check which results you will show using this log for all app you use do detect installer package name:
final PackageManager pm = getPackageManager();
//get a list of installed apps.
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo packageInfo : packages) {
String is = pm.getInstallerPackageName(packageInfo.packageName);//getPackageName());
Log.d(TAG, (packageInfo.packageName==null?"":packageInfo.packageName) + " : " + (is==null?"":is));
}
You will see the full list of installed apps & package sources, or log this data in your way your want.
EDIT
#Virus, i just want to give you a simple idea. if you want to know package installer name, you can just grab this data when you app is launched and send it to your own server using simple http GET request in order to detect the installer name. Republish you apo with this simple frabber. I think this the one solution.
I'm trying to use Google Tag Manager to report screenviews and events to Google Analytics. I followed the google's tutorial but I'm not able to even report the screenviews.
Also spent hours searching in google but there was no match. Almost all the information available is for Android's v3 or the old GTM web interface.
This is my configuration
Pushing the event to the data layer throws no error. However screenName seems not been sent.
Java code
public static void pushScreenViewEvent(#NonNull Context context, #NonNull String screenName) {
DataLayer dataLayer = TagManager.getInstance(context).getDataLayer();
dataLayer.pushEvent("screenView",
DataLayer.mapOf("screenName", screenName));
}
Debug log after push data
02-23 19:12:39.376 31787-31888/com.example.debug V/GoogleTagManager﹕ Sending hit to service PATH: https: PARAMS: sr=1080x1776, a=558676027, v=1, ht=1424686354314, an=Example app, ul=ja-jp, t=appview, _u=.L, tid=UA-XXXXXX-1, cid=XXXXXX, aid=com.example.debug, av=1.0.0,
Google Play Services version
compile 'com.google.android.gms:play-services-base:6.5.87'
There's this tutorial but it is for the old GTM v3 with the old GTM web screenshots
https://developers.google.com/tag-manager/android/v3/ua#screenviews
Ok, it was my fault.
There was two problems.
Fields to set were wrong
In order to track the screen in GA it's necessary to set the Screen Name's Measurement protocol parameter &cd
In my case Client Id and User Id are also necessary, that's why I send &ci and &uid
I was using a default binary container from a different test account. After use the correct container it worked like a charm.
It seems like firing rule is incorrect.
Try something like {{event}} equals screenView or Always as firing rule.
And it will take 24hrs to update in the Google Analytics dashboard, so it will not appear in the real time. Let me know if it doesn't work.