tapglue / android_sdk Goto Github PK
View Code? Open in Web Editor NEWTapglue Android SDK
Home Page: https://developers.tapglue.com/docs/android
Tapglue Android SDK
Home Page: https://developers.tapglue.com/docs/android
FATAL EXCEPTION: main
Process: com.dawanda.shopping.app.internal, PID: 26744
java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.tapglue.networking.requests.TGRequestCallback
at com.tapglue.utils.TGErrorUtil.sendErrorToCallbacks(TGErrorUtil.java:46)
at com.tapglue.networking.TGNetworkManager.performRequest(TGNetworkManager.java:390)
at com.tapglue.networking.TGNetworkManager.performRequest(TGNetworkManager.java:360)
at com.tapglue.networking.TGRequestFactory.logout(TGRequestFactory.java:333)
at com.tapglue.managers.TGUserManager.logout(TGUserManager.java:201)
When calling Tapglue.user().logout(new TGRequestCallback<Boolean>{});
while offline.
User social ids are a map between the social network and their ID on that network.
As such, the field should be changed from array to map<string, string>
Thank you.
One should be able to set a custom algorithm which can be used to hash the password as well
In general this will update the SDK to version 1.1 being compatible with the Tapglue API 0.4.
As in the project before. The iOS SDK is the template/blueprint for the Implementation if the following document is missing specification details. The documentation regarding the iOS details can be found here.
The new models for this API version contain:
The specification and attributes of the new entities are below.
The endpoints that are currently missing are specified in this document. This document the most important in this specification as it shows all the gaps and differences in the current Android SDK.
Naming inconsistencies are also marked (red) in that document. They should be aligned with the iOS SDK API, wherever reasonable.
This section describes the basic changes that need to be done.
1.0
to 1.1.0
setUnhashedPassword
method to user to set a password that is not PBKDF2
hashed.tg_object_id
to the events model.Tapglue.connections()
to Tapglue.connection()
(singular to be consistent)feed()
to connection()
:unFriend
to unfriend
unFollow
to unfollow
Tapglue.connection().retrieveConfirmedConncetionsForCurrentUser
Tapglue.connection().retrieveRejectedConncetionsForCurrentUser
We've added a new API for Posts, Comments on Posts and Likes on Posts and Shares of Posts.
The API now allows the creation of posts. Posts support the basic CRUD
as well as retrieving a list of posts for different endpoints.
Following methods should be available after the implementation of the Posts API.
Posts
Comments
Likes
The following section describes the models for Posts, Comments and Likes.
Write
Key | Type | Description | Example |
---|---|---|---|
tags | array | Contains an array of strings which describe tags of a post | "tags": ["fitness","running"] |
visibility | int | Visibility of posts (10,20,30) | "visibility": 30 |
attachments | array | Contains various attachments of a post (text, url) | example below |
Attachments example
"attachments": [
{
"content": "http://bit.ly/123gif",
"name": "teaser",
"type": "url"
},
{
"content": "Lorem ipsum...",
"name": "body",
"type": "text
}
],
"tags": [
"review"
]
The attachment structure is always the same:
currently we support text
and url
as the type. In the future we will allow more types such as audio, video, image etc. In this case content will always be a url.
Read only
Key | Type | Description | Example |
---|---|---|---|
id | string | Id of the post | "id": "12743631303647839" |
user_id | string | Id of the user who created post | "user_id": "11286878691041887" |
is_liked | bool | Flag wether the posts is liked or not | "is_liked": true |
created_at | string | Created at date | "created_at": "2015-11-27T16:03:36.171840385Z" |
updated_at | string | Created at date | "updated_at": "2015-11-27T16:03:36.171840478Z |
The user of the post should be accessible like in events Post.user.username
etc.
Addition read only keys for counts are:
"counts": {
"comments": 3,
"likes": 12,
"shares": 1
}
We don't return the counts yet. So the values should just be 0 if nothing is being returned from the API. However we will soon enable this feature from our backend
Write
Key | Type | Description | Example |
---|---|---|---|
content | string | Content of the comment | "content": "very nice post!" |
Read only
Key | Type | Description | Example |
---|---|---|---|
id | string | Id of the like | "id": "12743631303647840" |
post_id | string | Id of the post | "id": "12743631303647839" |
user_id | string | Id of the user who created post | "user_id": "11286878691041887" |
created_at | string | Created at date | "created_at": "2015-11-27T16:03:36.171840385Z" |
updated_at | string | Created at date | "updated_at": "2015-11-27T16:03:36.171840478Z |
Read only
Key | Type | Description | Example |
---|---|---|---|
id | string | Id of the comment | "id": "12743631303647840" |
post_id | string | Id of the post | "id": "12743631303647839" |
user_id | string | Id of the user who created post | "user_id": "11286878691041887" |
created_at | string | Created at date | "created_at": "2015-11-27T16:03:36.171840385Z" |
updated_at | string | Created at date | "updated_at": "2015-11-27T16:03:36.171840478Z |
Overview of endpoints:
Name | Method | Route |
---|---|---|
Create Post | POST |
/posts |
Retrieve Post | GET |
/posts/{postID} |
Update Post | PUT |
/posts/{postID} |
Delete Post | DELETE |
/posts/{postID} |
Retrieve all Posts | GET |
/posts |
Retrieve Posts Feed | GET |
/me/feed/posts |
Retrieve my Posts | GET |
/me/posts |
Retrieve users Posts | GET |
/users/{userID}/posts |
Name | Method | Route |
---|---|---|
Create Comment | POST |
/posts/{postID}/comments |
Update Comment | PUT |
/posts/{postID}/comments/{commentID} |
Delete Comment | DELETE |
/posts/{postID}/comments/{commentID} |
Retrieve Comments | GET |
/posts/{postID}/comments |
Name | Method | Route |
---|---|---|
Create Like | POST |
/posts/{postID}/likes |
Delete Like | DELETE |
/posts/{postID}/likes |
Retrieve Likes | GET |
/posts/{postID}/likes |
Deletion of likes is idempotent, so there is no id needed.
Post creation
curl -X POST /posts \
-d $'
{
"attachments": [
{
"content": "http://bit.ly/123gif",
"name": "teaser",
"type": "url"
},
{
"content": "Lorem ipsum...",
"name": "body",
"type": "text
}
],
"tags": [
"review"
],
"visibility": 30
}
'
201 Created
{
"attachments": [
{
"content": "http://bit.ly/123gif",
"name": "teaser",
"type": "url"
},
{
"content": "Lorem ipsum...",
"name": "body",
"type": "text
}
],
"id": "12743631303647839",
"tags": [
"review"
],
"visibility": 30,
"user_id": "11286878691041887",
"created_at": "2015-11-27T16:03:36.171840385Z",
"updated_at": "2015-11-27T16:03:36.171840478Z"
}
Comment creation
curl -X POST /posts/12743631303647839/comments \
-d $'
{
"content": "Do like.",
}
'
201 Created
{
"content": "Do like.",
"id": "12743631303647840",
"post_id": "12743631303647839",
"user_id": "11286878691041888",
"created_at": "2015-11-27T16:03:36.171840385Z",
"updated_at": "2015-11-27T16:03:36.171840478Z"
}
Comment retrieval
curl -X GET /posts/12743631303647839/comments
200 OK
{
"comments": [
{
"content": "Do like.",
"id": "12743631303647840",
"post_id": "12743631303647839",
"user_id": "11286878691041888",
"created_at": "2015-11-27T16:03:36.171840385Z",
"updated_at": "2015-11-27T16:03:36.171840478Z"
}
],
"comments_count": 1,
"post": {
"attachments": [
{
"content": "http://bit.ly/123gif",
"name": "teaser",
"type": "url"
},
{
"content": "Lorem ipsum...",
"name": "body",
"type": "text
}
],
"id": "12743631303647839",
"tags": [
"review"
],
"visibility": 30,
"user_id": "11286878691041887",
"created_at": "2015-11-27T16:03:36.171840385Z",
"updated_at": "2015-11-27T16:03:36.171840478Z"
}
}
Comment deletion
curl -X DELETE /posts/12743631303647839/comments/12743631303647840
204 No Content
Like creation
curl -X POST /posts/12743631303647839/likes \
-H 'Content-Length: 0'
201 Created
{
"id": "37363583381716140",
"post_id": "12743631303647839",
"user_id": "11286878691041888",
"created_at":"2015-03-21T14:28:02.4+01:00",
"updated_at":"2015-03-21T14:28:02.4+01:00"
}
Like retrieval
curl -X GET /posts/12743631303647839/likes
200 OK
{
"likes": [
{
"id": "37363583381716140",
"post_id": "12743631303647839",
"user_id": "11286878691041888",
"created_at":"2015-03-21T14:28:02.4+01:00",
"updated_at":"2015-03-21T14:28:02.4+01:00"
}
],
"likes_count": 1,
"post": {
"attachments": [
{
"content": "http://bit.ly/123gif",
"name": "teaser",
"type": "url"
},
{
"content": "Lorem ipsum...",
"name": "body",
"type": "text
}
],
"id": "12743631303647839",
"tags": [
"review"
],
"visibility": 30,
"user_id": "11286878691041887",
"created_at": "2015-11-27T16:03:36.171840385Z",
"updated_at": "2015-11-27T16:03:36.171840478Z"
}
}
Like deletion
curl -X DELETE /posts/12743631303647839/likes/37363583381716140
204 No Content
We have a new API that allows to search for multiple emails or socialIDs. Examples:
Tapglue.user().searchUsersWithEmails
curl -X "GET" "https://api.tapglue.com/0.4/users/search?email=jonelle.bowers%40rccgmail.org&email=nu.cardamone%40mycabin.com" \
-H "Accept: application/json" \
-H "Authorization: Basic OWQ0ZjgzNjNjZTFmZDExMTM4NDUyMmE5NWNkZjZiM2Y6SzJCT2FTRjRJbU1yWVZGaU9pOUlPWDB2VG1ZPQ=="
Tapglue.user().searchUsersWithSocialUserIds
curl -X "GET" "https://api.tapglue.com/0.4/users/search?social_platform=facebook&socialid=fb54321123&socialid=fb543211234" \
-H "Accept: application/json" \
-H "Authorization: Basic OWQ0ZjgzNjNjZTFmZDExMTM4NDUyMmE5NWNkZjZiM2Y6SzJCT2FTRjRJbU1yWVZGaU9pOUlPWDB2VG1ZPQ=="
The goal is to implement to new methods:
Due to the introduction of posts, the new feed structure changed a little bit.
The new feeds structure will look like the following:
me/feed
-> posts
& events
me/feed/posts
-> posts
me/feed/events
-> events
for users
me/events
& users/:userID/events
me/posts
& users/:userID/posts
The new me/feed
will have both posts
and events
. The other endpoints have either posts
or events
.
The names of the methods should be as follows:
me/feed
-> Tapglue.feed().retrieveNewsFeedForCurrentUser
me/feed/posts
-> Tapglue.feed().retrievePostsFeedForCurrentUser
me/feed/events
-> Tapglue.feed().retrieveEventsFeedForCurrentUser
me/events
-> Tapglue.feed().retrieveEventsForCurrentUser
users/:userID/events
-> Tapglue.feed().retrieveEventsForUser
me/posts
-> Tapglue.feed().retrievePostsForCurrentUser
users/:userID/posts
-> Tapglue.feed().retrievePostsForUser
Besides the default feed()
methods above. There should be another additional method that also accepts a query object. The query is a JSON object and need to be attached to endpoint after ?where=
clause. Here is an example of a query object:
{
"object":{
"id":{
"eq":"someId"
}
},
"type":{
"eq":"someType"
}
}
The query object always contains the field, that is to be checked (i.e. type) followed by the request condition eq and then the value someType. For now, the only request condition is eq but there are more to come in the future. Fields that are checkable are currently:
As a request condition we currently support two:
eq, contains a single string. in contains an array of strings.
Example for in:
{
"type":{
"in":["someType","anotherType"]
}
}
On TGEvent
the location and priority fields have incorrect SerializedNames values.
@Expose
@SerializedName("mLocation")
private String mLocation;
@Expose
@SerializedName("mPriority")
private String mPriority;
@Expose
@SerializedName("location")
private String mLocation;
@Expose
@SerializedName("priority")
private String mPriority;
I'm not sure if others need to be fixed as well. I only ran into the problem that the location was serialized incorrectly.
I'm happy to put a PR out later.
https://github.com/tapglue/android_sdk/blob/master/tapglue-android-sdk/src/main/AndroidManifest.xml
<application>
with params like android:fullBackupContent="true"
The lack of proper tests means we can't get an idea of the coverage the project has, which is bad for the soul. This should be fixed.
10-29 18:41:31.524 26707-26790/com.tapglue.example D/OkHttp: --> POST https://api.tapglue.com/0.4/users http/1.1
10-29 18:41:31.524 26707-26790/com.tapglue.example D/OkHttp: Content-Type: application/json; charset=UTF-8
10-29 18:41:31.524 26707-26790/com.tapglue.example D/OkHttp: Content-Length: 174
10-29 18:41:31.524 26707-26790/com.tapglue.example D/OkHttp: Authorization: Basic MmRhMmQ3OTMzNmMyNzczYzYzMGNlNDZmNWQyNGNiNzY6
10-29 18:41:31.524 26707-26790/com.tapglue.example D/OkHttp: X-Tapglue-OS: Android
10-29 18:41:31.525 26707-26790/com.tapglue.example D/OkHttp: X-Tapglue-OSVersion: 7.0
10-29 18:41:31.525 26707-26790/com.tapglue.example D/OkHttp: X-Tapglue-Manufacturer: motorola
10-29 18:41:31.525 26707-26790/com.tapglue.example D/OkHttp: X-Tapglue-Model: Moto G (4)
10-29 18:41:31.525 26707-26790/com.tapglue.example D/OkHttp: X-Tapglue-SDKVersion: 3.0.5
10-29 18:41:31.525 26707-26790/com.tapglue.example D/OkHttp: X-Tapglue-AndroidID: 4cf58a47-7078-49dc-a92e-acba751920b3
10-29 18:41:31.525 26707-26790/com.tapglue.example D/OkHttp: X-Tapglue-Timezone: Asia/Calcutta
10-29 18:41:31.525 26707-26790/com.tapglue.example D/OkHttp: {"enabled":true,"followed_count":0,"follower_count":0,"friend_count":0,"is_followed":false,"is_follower":false,"is_friend":false,"password":"supersecret","user_name":"pablo"}
10-29 18:41:31.525 26707-26790/com.tapglue.example D/OkHttp: --> END POST (174-byte body)
10-29 18:41:31.530 26707-26790/com.tapglue.example D/OkHttp: <-- HTTP FAILED: java.net.UnknownHostException: Unable to resolve host "api.tapglue.com": No address associated with hostname
When I call Tapglue.user().createAndLoginUser()
method with TGUser
provided, I receive an error. Android Logcat shows:
D/OkHttp: {"errors":[{"code":4001,"message":"authentication error"}]}
The call always fails.
This lib get's exported as an aar instead of a jar withouth the need to do so.
As a dev I'd like to be able to do threading myself. All interaction should also have a method executed on the calling thread.
I'm creating a new TGEvent and I'm setting the metadata value. I see that it is serialized correctly but it is not included in the response.
TGEvent event = new TGEvent()
.setType("like")
.setLanguage("en")
.setLocation("berlin")
.setVisibility(TGEvent.TGEventVisibility.Global)
.setMetadata("some metadata");
Request:
{
"language": "en",
"location": "berlin",
"metadata": "Testing - 1452094991328",
"type": "like",
"user_id": 18291535703445665,
"visibility": 40
}
Response:
{
"id_string": "18539782648893028",
"tg_object_id": "0",
"user_id_string": "18291535703445665",
"id": 18539782648893028,
"user_id": 18291535703445665,
"type": "like",
"language": "en",
"location": "berlin",
"visibility": 40,
"object": null,
"object_id": 0,
"owned": false,
"created_at": "2016-01-06T15:43:11.592759216Z",
"updated_at": "2016-01-06T15:43:11.592759216Z",
"enabled": true
}
This can be reproduced with the Tapglude Android example app.
If I issue a request to create a new event via curl, the metadata field is included in the response correctly.
If the metadata field actually includes a JSON object instead of a plain string, GSON cannot deserialize into a String. Should the field type be JsonObject
or a Map
?
Exception:
01-06 10:42:16.635 27715-27715/com.femlite.app E/Tapglue: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 691 path $.events[1].metadata
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 691 path $.events[1].metadata
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:221)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:117)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:217)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.Gson.fromJson(Gson.java:861)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.Gson.fromJson(Gson.java:826)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at retrofit.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:36)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at retrofit.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:24)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at retrofit.OkHttpCall.parseResponse(OkHttpCall.java:148)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at retrofit.OkHttpCall.access$100(OkHttpCall.java:29)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at retrofit.OkHttpCall$1.onResponse(OkHttpCall.java:94)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:177)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at java.lang.Thread.run(Thread.java:818)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: Caused by: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 691 path $.events[1].metadata
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.stream.JsonReader.nextString(JsonReader.java:838)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:422)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:410)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:117)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:217)
01-06 10:42:16.635 27715-27715/com.femlite.app W/System.err: ... 17 more
This and the hole ``/res` folder is there for no reason
java.lang.IllegalArgumentException: Unexpected char 0x15b at 5 in header value: Czas środkowoeuropejski standardowy
at com.squareup.okhttp.Headers$Builder.checkNameAndValue(Headers.java:295)
at com.squareup.okhttp.Headers$Builder.add(Headers.java:245)
at com.squareup.okhttp.Request$Builder.addHeader(Request.java:197)
at com.tapglue.networking.TGNetworkManager$1.intercept(TGNetworkManager.java:181)
at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:232)
at com.squareup.okhttp.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:204)
at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:232)
at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:205)
at com.squareup.okhttp.Call.access$100(Call.java:35)
at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:171)
at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
SDK ver 1.1.6
compile 'com.android.support:appcompat-v7:23.1.1'
in sdk build.gradle should be replaced with
compile 'com.android.support:support-annotations:23.1.1'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.