Cloud Endpoints generate entity key inside of Android/iOS client libs - android

Is there a way inside of Android Java to create an Entity Key?
For example, inside the Cloud Endpoints Java module code you can do this:
Key<User> userKey= Key.create(User.class, userId);
or with an Ancestor:
Key<Post> postKey= Key.create(userKey, Post.class, postId);
How can you do the above in the Android generated client library? I want to see if I can create a key in Android and pass it to an API method (probably as a websafeKey userKey.getString()).
BONUS: How can you do this with the objective-C Cloud Endpoints client library?

I doubt you want either the datastore nor objectify code in your Android App. That simply not where that belongs. So the way to go is to look at the source of the KeyFactory. In the method keyToString() we can see that most of the magic happens in the class KeyTranslator in method convertToPb().
Here's the code of convertToPb:
public static Reference convertToPb(Key key) {
Reference reference = new Reference();
reference.setApp(key.getAppId());
String nameSpace = key.getNamespace();
if (!nameSpace.isEmpty()) {
reference.setNameSpace(nameSpace);
}
Path path = reference.getMutablePath();
while (key != null) {
Element pathElement = new Element();
pathElement.setType(key.getKind());
if (key.getName() != null) {
pathElement.setName(key.getName());
} else if (key.getId() != Key.NOT_ASSIGNED) {
pathElement.setId(key.getId());
}
path.addElement(pathElement);
key = key.getParent();
}
Collections.reverse(path.mutableElements());
return reference;
}
And here's the code of keyToString()
public static String keyToString(Key key) {
if (!key.isComplete()) {
throw new IllegalArgumentException("Key is incomplete.");
} else {
Reference reference = KeyTranslator.convertToPb(key);
return base64Url().omitPadding().encode(reference.toByteArray());
}
}
Now what you want to do, is to replace the Key stuff in convertToPb with "normal" parameters (type, name/key, parent type, parent name/key) and thus rewrite the method to create a websafeKey without an actual Key object.
It would be much easier though if your app engine API simply accepted the ids and you'd recreate the key on the appengine side of things. My APIs are usually structured like
/user/<userId>/post/<postId>
if i assume an Entity that looks like this
#Entity public class Post {
#Parent Ref<User> user
#Id id; }
Regarding the bonus: What (the heck) is an Objectify Cloud Endpoint? I know Cloud Endpoints and Objectify, but i have not heard of a product that combines the two.

Related

Apollo Client response not in JSON format for GitHub GraphQL APIs

I am experimenting with GraphQL on Android using apollo-client and am using GitHub's GraphQL API. I am hitting an API to give me a list of repos owned by a user. Everything works fine but the response that I get is not in JSON format but in String format.
The response looks like this:
Data{user=User{__typename=User,
repositories=Repositories{__typename=RepositoryConnection, nodes=
[Node{__typename=Repository, name=testrepository}]}}
when I try hitting the url through Insomnia (GraphQL rest client) I get the response in JSON format but in my app I get the response in above format. I tried passing content-type : "application/json; charset=utf-8" in header but no success.
Here is how I am fetching the response:
public void fetchRepoList(String userName, String authHeader, final ResponseCallback responseCallback) {
GraphQL.getInstance().getApolloClient(authHeader)
.query(githubRepoList.repoListAPI.FindQuery.builder().repoOwner(userName).build())
.enqueue(new ApolloCall.Callback<githubRepoList.repoListAPI.FindQuery.Data>() {
#Override
public void onResponse(#Nonnull Response<githubRepoList.repoListAPI.FindQuery.Data> response) {
Log.d(TAG, "response" + response)
}
#Override
public void onFailure(#Nonnull final ApolloException exception) {
}
});
}
I want to put the response in a List of Model class and for that I need the response in JSON format. Searched for this issue but didn't got any proper solution.
I am using apollo client 0.3.2
[Edit:1]
I tried making the call to the GitHub GraphQL API with Okhttp and this time I got this response:
{"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":{"name":"Mutation"},"subscriptionType":null,"types":[{"kind":"SCALAR","name":"Boolean","description":"Represents `true` or `false` values.","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"String","description":"Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Query","description":"The query root of GitHub's GraphQL interface.","fields":[{"name":"codeOfConduct","description":"Look up a code of conduct by its key","args":[{"name":"key","description":"The code of conduct's key","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"CodeOfConduct","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"codesOfConduct","description":"Look up a code of conduct by its key","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"CodeOfConduct","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"license","description":"Look up an open source license by its key","args":[{"name":"key","description":"The license's downcased SPDX ID","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"License","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"licenses","description":"Return a list of known open source licenses","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"License","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"marketplaceCategories","description":"Get alphabetically sorted list of Marketplace categories","args":[{"name":"includeCategories","description":"Return only the specified categories.","type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}}},"defaultValue":null},{"name":"excludeEmpty","description":"Exclude categories with no listings.","type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":null},{"name":"excludeSubcategories","description":"Returns top level categories only, excluding any subcategories.","type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":null}],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"MarketplaceCategory","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"marketplaceCategory","description":"Look up a Marketplace category by its slug.","args":[{"name":"slug","description":"The URL slug of the category.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null},{"name":"useTopicAliases","description":"Also check topic aliases for the category slug","type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":null}],"type":{"kind":"OBJECT","name":"MarketplaceCategory","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"marketplaceListing","description":"Look up a single Marketplace listing","args":[{"name":"slug","description":"Select the listing that matches this slug. It's the short name of the listing used in its URL.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"MarketplaceListing","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"marketplaceListings","description":"Look up Marketplace listings","args":[{"name":"after","description":"Returns the elements in the list that come after the specified cursor.","type"
This response doesn't even have required data about the repositories. It is not even related to the list of repositories.
Therefore, I went back to the old method and made the call using apollo. Now, since apollo creates these model classes from standard GraphQL queries, how do I create a list of this model class.
I went through the apollo sample-app on github and came across this piece of code:
List<FeedEntry> feedResponseToEntriesWithRepositories(Response<FeedQuery.Data> response) {
List<FeedEntry> feedEntriesWithRepos = new ArrayList<>();
final FeedQuery.Data responseData = response.data();
if (responseData == null) {
return Collections.emptyList();
}
final List<FeedEntry> feedEntries = responseData.feedEntries();
if (feedEntries == null) {
return Collections.emptyList();
}
for (FeedEntry entry : feedEntries) {
if (entry.repository() != null) {
feedEntriesWithRepos.add(entry);
}
}
return feedEntriesWithRepos;
}
Here the feedEntries() method returns the list of feeds, this method is in the auto-generated model class file in the apollo directory. I went and checked my model file and there were no methods which returns a list of repos (as in my case). The file is too large to post here but if community want's to have a look at it I can post it here.
By the way, I tried something like this with my code:
List<githubRepoList.repoListAPI.FindQuery.Node> repoList = new ArrayList<>();
final githubRepoList.repoListAPI.FindQuery.Data repoListData = response.data();
final List<githubRepoList.repoListAPI.FindQuery.Node> finalRepoList = repoListData.(which method to call from the auto-generated class file?)
Here, Node is a class in my auto-generated model file in the apollo directory and this class should have a method which returns a list of repo model class.
I know I am doing something wrong here. I think there is some other way to create of list of these model classes.
the response is not in JSON format
The response was in JSON format. It is now in the form of a githubRepoList.repoListAPI.FindQuery.Data object. That class was code-generated for you based on your GraphQL document. Quoting the Apollo-Android documentation, with emphasis added:
Apollo-Android is a GraphQL compliant client that generates Java models from standard GraphQL queries
In particular, Apollo-Android generates toString() implementations on those Java model classes. In your case:
Data holds a User in a user field
User holds a RepositoriesConnection, renamed to Repositories, in a repositories field
The repositories collection holds a single Repository
The reason for using Apollo-Android is so that you do not have to deal with the JSON yourself. If, instead, you want to parse JSON yourself, get rid of Apollo-Android and just use OkHttp to make the Web service calls.

Generate referral short links using Branch SDK android

I want to implement a referral system in my app using branch SDK. I want to generate a short link with my static custom endpoint (https://app.link/ABC123) for each user which can be shared by other users. I can do this by setting alias on LinkProperties. But using alias with BUO.showShareSheet gives an error.
Can I use an alias with BUO.showShareSheet?
Should the Canonical identifier unique for each URL?
Is it possible to set multiple channels using LinkProperties?
Does the same URL generate every time if all arguments are same for BUO & LinkProperties?
1. Can I use an alias with BUO.showShareSheet?
You can definitely use alias with the showShareSheet method. Here is the code I used to generate and share an alias link
final BranchUniversalObject branchUniversalObject = new BranchUniversalObject()
.setCanonicalIdentifier("/1234")
.setTitle("Test for alias")
.setContentDescription("Your friend has invited you to check out my app!") .setContentImageUrl("https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Branch_Metrics_logo_color.png/1200px-Branch_Metrics_logo_color.png")
.addContentMetadata("var1", "abc")
.addContentMetadata("var2", "def");
LinkProperties linkProperties = new LinkProperties()
.setChannel("Facebook")
.setFeature("Sharing")
.setAlias("aliastest");
ShareSheetStyle ss = new ShareSheetStyle(MainActivity.this, "Check this out!", "This stuff is awesome: ")
.setCopyUrlStyle(ContextCompat.getDrawable(this, android.R.drawable.ic_menu_send), "Copy", "Added to clipboard")
.setMoreOptionStyle(ContextCompat.getDrawable(this, android.R.drawable.ic_menu_search), "Show more")
.addPreferredSharingOption(SharingHelper.SHARE_WITH.FACEBOOK)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.EMAIL)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.MESSAGE)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.HANGOUT)
.setAsFullWidthStyle(true)
.setSharingTitle("Share With");
branchUniversalObject.showShareSheet(this, linkProperties, ss, new Branch.BranchLinkShareListener() {
#Override
public void onShareLinkDialogLaunched() {
}
#Override
public void onShareLinkDialogDismissed() {
}
#Override
public void onLinkShareResponse(String sharedLink, String sharedChannel, BranchError error) {
}
#Override
public void onChannelSelected(String channelName) {
}
});
But please note, if you try to generate a link with the same alias and different link parameters, you will receive an alias conflict error and the showShareSheet method would, in turn, give you an error.
2. Should the Canonical identifier unique for each URL?
The canonicalIdentifier or canonicalUrl parameter greatly improves the content analytics data Branch captures. Branch suggests that it should be unique to that piece of content. It, in turn, helps Branch dedupe across many instances of the same thing. Suitable options: a website with pathing, or a database with identifiers for entities.
3. Is it possible to set multiple channels using LinkProperties?
You cannot set multiple channels for a single link. The channel tag is used to signify the route that your link reaches users. Hence, there can be only one channel.
4. Does the same URL generate every time if all arguments are same for BUO & LinkProperties?
If all the BranchUniversalObject properties and link properties are exactly the same, the generateShortUrl and showShareSheet will return the same link.

unity android gameobject not working

So in my app i pass a game object, called datacontroller through out my three scenes. The persistent scene is an empty scene, the menuscreen scene and then the game scene. My application works perfectly on my computer and in editor mode but when i download the apk to my android tablet it no longer works! iv'e read this may have to do with my code for my object but i dont think i written anything that only works in the editor.
enter code here
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
using System.IO; // The System.IO namespace contains functions related to loading and saving
files
public class DataController : MonoBehaviour
{
private RoundData[] allRoundData;
private PlayerProgress playerProgress;
private string gameDataFileName = "data.json";
void Start()
{
DontDestroyOnLoad(gameObject);
LoadGameData();
LoadPlayerProgress();
SceneManager.LoadScene("MenuScreen");
}
public RoundData GetCurrentRoundData()
{
// If we wanted to return different rounds, we could do that here
// We could store an int representing the current round index in PlayerProgress
return allRoundData[0];
}
public void SubmitNewPlayerScore(int newScore)
{
// If newScore is greater than playerProgress.highestScore, update playerProgress with the new value and call SavePlayerProgress()
if (newScore > playerProgress.highestScore)
{
playerProgress.highestScore = newScore;
SavePlayerProgress();
}
}
public int GetHighestPlayerScore()
{
return playerProgress.highestScore;
}
private void LoadGameData()
{
// Path.Combine combines strings into a file path
// Application.StreamingAssets points to Assets/StreamingAssets in the Editor, and the StreamingAssets folder in a build
string filePath = Path.Combine(Application.streamingAssetsPath, gameDataFileName);
if (File.Exists(filePath))
{
// Read the json from the file into a string
string dataAsJson = File.ReadAllText(filePath);
// Pass the json to JsonUtility, and tell it to create a GameData object from it
GameData loadedData = JsonUtility.FromJson<GameData>(dataAsJson);
// Retrieve the allRoundData property of loadedData
allRoundData = loadedData.allRoundData;
}
else
{
Debug.LogError("Cannot load game data!");
}
}
// This function could be extended easily to handle any additional data we wanted to store in our PlayerProgress object
private void LoadPlayerProgress()
{
// Create a new PlayerProgress object
playerProgress = new PlayerProgress();
// If PlayerPrefs contains a key called "highestScore", set the value of playerProgress.highestScore using the value associated with that key
if (PlayerPrefs.HasKey("highestScore"))
{
playerProgress.highestScore = PlayerPrefs.GetInt("highestScore");
}
}
// This function could be extended easily to handle any additional data we wanted to store in our PlayerProgress object
private void SavePlayerProgress()
{
// Save the value playerProgress.highestScore to PlayerPrefs, with a key of "highestScore"
PlayerPrefs.SetInt("highestScore", playerProgress.highestScore);
}
}
I am starting to go through tutorials of unity myself so I am not an expert. :)
But what I would try is the first thing. using System.IO; not sure if this will work to get files on android because android has a different file structure. So I would first remove it and sort of hard code the file path or comment out the code using System.IO classes then recompile apk in unity and check if it works. I also saw this post : http://answers.unity3d.com/questions/1023391/systemio-dont-work-on-android.html
If that did not work I would comment functionality out and compile apk and check if its working if its not comment more code out until you find the line or the code that causes it to error on android. This method takes long to troubleshoot or get your code causing the problem but for me this has worked before.
I am guessing as it is working on you pc its a class or something its referencing that's not available in android.
Please share your findings if you figure out what part of the code does it. As I would also want to know to prevent me from doing it. :)
Avoid the use of System.IO on Android and in general on Unity.
Use "Resources" instead, just following this steps:
Create a folder called "Resources"
Move json file on it and rename in .txt
Use this code to get the string:
var file = Resources.Load("filename_here") as TextAsset;
Debug.Log(file.text)

Getting card funding parameter from Stripe Android API

I an using the Stripe Android API to process payments in a mobile application. When a user registers for the app, a Stripe token is generated based on their credit card information. As per the requirement of the project, the app needs to reject prepaid credit cards from being used. Unfortunately, the Android API does not give access to the funding parameter of the Card object returned from the stripe token. This parameter states weather the card is prepaid, debit or credit.
Does anyone know how to access this information on Android? If this is not possible using the Stripe Android API, is there anyway I can directly access the JSON object returned from the Stripe API?
The Stripe Android bindings do not directly expose the card object from the API (which has the funding attribute you're interested in), but you can retrieve it by the token ID using the Java bindings. Something like this should work:
public void onSuccess(Token token) {
com.stripe.model.Token stripeToken = com.stripe.model.Token.retrieve(token.getId(), publishableKey);
com.stripe.model.Card stripeCard = stripeToken.getCard();
if (stripeCard.getFunding().equals("prepaid") {
// Reject card
}
}
Note that this is basically what the Android bindings do when creating the token in the first place (see here).
EDIT: After investigating a bit further, I'm not so sure the above will work. While there is a requestToken() method in the Android bindings that calls the retrieve token API with the publishable key (see here), I don't think it actually works. Calling this endpoint with a publishable key results in an error indicating that the secret key should be used. (I guess it was an undocumented behavior that was removed at some point.)
If this is the case, then I guess you have two options:
patch the Android bindings to make the funding property from the API object available in the Android object (at creation time), or
make the check server-side.
What about this? I used Ywain answer and put it into Async like Stripe SDK do. Works for me.
private class CreateStripeTokenTask extends AsyncTask<Void, Void, com.stripe.model.Token> {
private Map<String, Object> mMap;
protected CreateStripeTokenTask(Card card) {
mMap = hashMapFromCard(card);
}
#Override
protected com.stripe.model.Token doInBackground(Void... params) {
try
{
RequestOptions requestOptions = RequestOptions.builder().setApiKey(<YOUR_STRIPE_PUBLISHABLE_KEY>).build();
com.stripe.model.Token stripeToken = com.stripe.model.Token.create(mMap, requestOptions);
return stripeToken;
}
catch (Exception e)
{
return null;
}
}
protected void onPostExecute(com.stripe.model.Token stripeToken) {
if (stripeToken != null && stripeToken.getCard() != null)
{
if ("prepaid".equals(stripeToken.getCard().getFunding()))
{
//error - prepaid cards are not eligible
}
else
{
//card is fine
}
}
}
private Map<String, Object> hashMapFromCard(Card card) {
Map<String, Object> tokenParams = new HashMap<>();
Map<String, Object> cardParams = new HashMap<>();
cardParams.put("number", TextUtils.nullIfBlank(card.getNumber()));
cardParams.put("cvc", TextUtils.nullIfBlank(card.getCVC()));
cardParams.put("exp_month", card.getExpMonth());
cardParams.put("exp_year", card.getExpYear());
cardParams.put("name", TextUtils.nullIfBlank(card.getName()));
cardParams.put("currency", TextUtils.nullIfBlank(card.getCurrency()));
cardParams.put("address_line1", TextUtils.nullIfBlank(card.getAddressLine1()));
cardParams.put("address_line2", TextUtils.nullIfBlank(card.getAddressLine2()));
cardParams.put("address_city", TextUtils.nullIfBlank(card.getAddressCity()));
cardParams.put("address_zip", TextUtils.nullIfBlank(card.getAddressZip()));
cardParams.put("address_state", TextUtils.nullIfBlank(card.getAddressState()));
cardParams.put("address_country", TextUtils.nullIfBlank(card.getAddressCountry()));
// Remove all null values; they cause validation errors
for (String key : new HashSet<>(cardParams.keySet())) {
if (cardParams.get(key) == null) {
cardParams.remove(key);
}
}
tokenParams.put("card", cardParams);
return tokenParams;
}
}

Using JSON to create an object in Groovy/Grails

I have a Groovy/Grails website that is being used to send data to Android clients via JSON. I have created both the Android client and the Groovy/Grails website; and they can output the same objects in JSON.
I can successfully create the respective objects in Android by mapping the JSON output to Java objects, however I was wondering if it's possible to use the JSON output to create a new domain object in Groovy/Grails? Is there a way of passing the JSON output to a controller action so that object will be created?
Here is an example of the JSON that I'd like to send;
{
"class":"org.icc.callrz.BusinessCard.BusinessCard",
"id":1,
"businessCardDesigns":[],
"emailAddrs":[
{
"class":"org.icc.callrz.BusinessCard.EmailAddress",
"id":1,
"address":"chris#krslynx.com",
"businessCard":{
"_ref":"../..",
"class":"org.icc.callrz.BusinessCard.BusinessCard"
},
"index":0,
"type":{
"enumType":"org.icc.callrz.BusinessCard.EmailAddress$EmailAddressType",
"name":"H"
}
},
{
"class":"org.icc.callrz.BusinessCard.EmailAddress",
"id":2,
"address":"cb#i-cc.cc",
"businessCard":{
"_ref":"../..",
"class":"org.icc.callrz.BusinessCard.BusinessCard"
},
"index":1,
"type":{
"enumType":"org.icc.callrz.BusinessCard.EmailAddress$EmailAddressType",
"name":"W"
}
}
]
}
The "class" matches to the Domain I'd like to save to, the ID is the ID of the Domain, then each item within the businessCardDesigns and emailAddrs needs to be saved using similar methods (in the Domain the businessCardDesigns and emailAddrs are ArrayLists). Many thanks in advance!
SOLUTION:
#RequestMapping(method = RequestMethod.POST, headers = "Accept=application/json")
public ResponseEntity<String> createFromJson(#RequestBody String json) {
Owner.fromJsonToOwner(json).persist();
return new ResponseEntity<String>(HttpStatus.CREATED);
}
Using the built-in Grails JSON converter makes this easier than the other answers, in my opinion:
import grails.converters.JSON
class PersonController {
def save = {
def person = new Person(JSON.parse(params.person))
person.save(flush:true)
}
}
The other benefits are:
There's no need to muck around in any config files
The resulting JSON object can be manipulated, if necessary, before assigning properties
It's far clearer in the code what's happening (we're parsing a JSON object and setting the properties on the Person entity)
I know you already accepted an answer but if I'm reading your question right, there's a built in "Grails" way to do this.
Create an entry for your action in URLMappings.groovy and turn on request parsing. For example, I create RESTful mappings like so:
"/api/bizCard/save"(controller: "businessCard", parseRequest: true) {
action = [POST: "save"]
}
And then in you controller
def save = {
def businessCardInstance = new BusinessCard(params.businessCard)
....
businessCardInstance.save(flush:true)
}
this might work for you
http://static.springsource.org/spring-roo/reference/html/base-json.html

Categories

Resources