Xamarin HttpClient - android

I'm using Xamarin Forms to consume REST Api from NetFlix but i get this issue in Popup:
System.Net.WebException: Error: NameResolutionFailure
Why o get this error?
My Code:
private HttpClient client = new HttpClient();
private List<Movie> movies;
public async Task<List<Movie>> LocalizaFilmesPorAtor(string ator)
{
if (string.IsNullOrWhiteSpace(ator))
{
return null;
}
else
{
string url = string.Format("http://netflixroulette.net/api/api.php?actor={0}", ator);
var response = await client.GetAsync(url);
if (response.StatusCode == HttpStatusCode.NotFound)
{
movies = new List<Movie>();
} else
{
var content = await response.Content.ReadAsStringAsync();
var _movies = JsonConvert.DeserializeObject<List<Movie>>(content);
movies = new List<Movie>(_movies);
}
return movies;
}
}
In debug mode said the error is in this code
string url = string.Format("http://netflixroulette.net/api/api.php?actor={0}", ator);
var response = await client.GetAsync(url);
He stops in there, the url recive the url + actor name but in next line the response stay null.
PS: I give Internet permission to my App in Manifest!

nuget packages: Microsoft HTTP Client Libraries and Newtonsoft.Json.
try this:
private HttpClient client = new HttpClient();
private List<Movie> movies;
public async Task<List<Movie>> LocalizaFilmesPorAtor(string ator)
{
if (string.IsNullOrWhiteSpace(ator))
{
return null;
}
else
{
var client = new HttpClient();
client.BaseAddress = new Uri("http://netflixroulette.net/");
HttpResponseMessage response = client.GetAsync("api/api.php?actor={0}", ator);
if(response.IsSuccessStatusCode)
{
var json = response.Content.ReadAsStringAsync().Result;
var _movies = JsonConvert.DeserializeObject<List<Movie>>(json);
movies = new List<Movie>(_movies);
}
else
{
movies = new List<Movie>();
}
return movies;
}
}
PS: if movies = new List(_movies) not work, try foreach.

Why cant you try Refit?
Refit is a library heavily inspired by Square's Retrofit library, and it turns your REST API into a live interface
What you just need to do is:
Add Refit from Nuget Package
Create an Interface with any name
Import the Refit (Using Refit)
here is a sample code for the interface
public interface ISampleName
{
[Get("api/api.php?actor={ator}")]
async Task<List<Movie>> LocalizaFilmesPorAtor(string ator);
}
After that, then you can call it this way:
var SampleNameApi = RestService.For<ISampleName>("http://netflixroulette.net/");
var response= await SampleNameApi.LocalizaFilmesPorAtor("Sample");
I believe this will help you.
For More Information https://github.com/paulcbetts/refit

I had this issue too because my URL was malformed. Double check if your URL is correct with Postman/Browser.

Related

KTor URLBuilder encodedPath with dynamic path

I'm trying to build a network module for Multiplatform project with ktor.
My code for GET request is something like this:
val result = httpClient.get<HttpResponse> {
url {
protocol = baseProtocol
host = baseUrl
encodedPath = urlPath
}
}
In some point my path contain a user id like this /users/{user_id}.
I can do a search and replace in string and replace this user_id with actual value, BUT is there any other way to do this? any ktor specific way.
For example with Retrofit we have this:
#GET("users/{user_id}/")
SomeData getUserData(#Path("user_id") String userId);
EDIT: adding more code
val result = httpClient.get<HttpResponse> {
url {
protocol = baseProtocol
host = baseUrl
var requestPath = request.requestPath.value
request.path?.forEach {
requestPath = requestPath.replace(it.first, it.second)
}
encodedPath = requestPath
if (request.parameters != null) {
parameters.appendAll(getParametersFromList(request.parameters))
}
}
the request.path?.forEach { requestPath = requestPath.replace(it.first, it.second)} replacing any runtime path value.

How to develop an android application separating data and view layer

I am new to Android development. have an android application in koltin wherein I have to make an http post request to get a list of data as response.
I have done that in activity class as follows.
MainActivity.kt
class MainActivity : AppCompatActivity(), {
private fun getAppList() {
var builder = AlertDialog.Builder(this#MainActivity)
builder.setTitle("App Response")
doAsync {
sslCertficate.disableSSLCertificateChecking()
var headers = HashMap<String, String>()
headers["Content-type"] = "application/json; charset=UTF-8"
val res = HTTPClient("https://sample-myapi-launcher.prod.com/list")
.setMethod("POST")
.setHeaders(headers)
.setBody(getRequestBody(userInfo.toString()))
.getResponse()
.response
uiThread {
builder.setMessage(res)
var dialog: AlertDialog = builder.create()
dialog.show()
}
Log.e("Response List", res)
}
}
private fun getRequestBody(userInfo: String): String {
//code for geting request body
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_navigator)
setSupportActionBar(toolbar)
//calling api request method
getAppList()
}
}
I could achieve my result through this, But I don't want to put all the work in the activity thread. Can someone guide on the correct approach to achieve this?
Or help me with some documentation.
This is the Android lifecycle-aware components codelab. It will do exatelly what you ask for. Here is the Architecture components part of the Android Jetpack and it is a set of Android libraries that help you structure your app in a way that is robust, testable, and maintainable.
Here is also the android-sunflower A gardening app illustrating Android development best practices with Android Jetpack.
to do networking I suggest you to use Retrofit2: Retrofit
Anyway to do networking operation in another thread you need to start a new AsyncTask from you activity and do the networking operations inside it.
In retrofit all this is much more simple!
(Sorry but I don't have Kotlin example for that below!)
Java Example without Retrofit:
( This was a my old project, so it isn't so good ^^)
/* Really Simple Class I made to do networking operations (so use Retrofit or make a better one (: (I suggest you, again, to use Retrofit!) */
public class DBConnection {
public String performPostCall(String requestURL, HashMap<String, String> postDataParams )
{
URL url;
String response = "";
try {
url = new URL(requestURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(15000);
conn.setConnectTimeout(15000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
conn.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
conn.connect();
DataOutputStream dStream = new DataOutputStream(conn.getOutputStream());
dStream.writeBytes(getPostDataString(postDataParams));
dStream.flush();
dStream.close();
int responseCode = conn.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line=br.readLine()) != null) {
response += line;
}
} else {
response = "";
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return response;
}
private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException
{
StringBuilder result = new StringBuilder();
boolean first = true;
for(Map.Entry<String, String> entry : params.entrySet()){
if (first) {
first = false;
} else {
result.append("&");
}
result.append(entry.getKey());
result.append("=");
result.append(entry.getValue());
}
return result.toString();
}
}
// AsyncTask to do Async Networking operations:
public class YourTask extends AsyncTask<String, Void, String> {
private String yourData...;
public YourTask(String token){
// Set Your Data
}
// "String..." is an array of arguments so you get the arguments usign: params[i]
#Override
protected String doInBackground(String... params)
{
DBConnection dbConn = new DBConnection();
String stampAnswer;
try{
Integer param1 = Integer.parseInt(params[0]);
Integer param2 = Integer.parseInt(params[1]);
answer = dbConn.netwokirngOperation([..]);
}catch(NumberFormatException nfe){
nfe.getStackTrace();
stampAnswer = "";
Log.e("YourTask", " NumberFormatException:");
}
return answer;
}
protected void onPostExecute(String result) {
Log.e("YourTask => ", " Result:" + result);
}
}
// To call the task do in your activity and do async networking operation without wait for result (this mean you need to save the data inside Realm DB [REALM][2] or using SQLite DB and then get them when the networking operations ended (you can use an Observable and set it when the networking operation end, send a broadcast message and set a receiver in you activity, or any other method):
new YourTask(<put_here_your_asynctask_constructor_args>).execute(params);
// To call the task and do async networking operation but wait to get the result returned by the "doInBackground" method of the AsyncTask:
new YourTask(<put_here_your_asynctask_constructor_args>).execute(params).get();
But is better if you use interface and callback to return the result from the AsyncTask when it ended, example:
/** in You Activity. Because in the Interface you use generic types (the 'T') you can specific the type of object returned by the interface inside the '<T>' if the interface WILL ALWAYS RETURN THE SAME OBJECT TYPE!
If it WILL RETURN DIFFERENT OBJECT TYPES you MUST don't specific the type inside the '<T>', but you have to cast the return inside a switch statement to know which object is returned (to do that you can add a 'int requestCase' to the interface so you know which case returned!) **/
public class YourActivity extends AppCompatActivity
implements IYourCallback<YourObjectTypesReturned>{
public interface IYourCallback<T>{
onNetOperationSuccess(List<T> answer)
onNetOperationError(Throwable t)
}
/** IMPLEMENTS HERE YOUR ACTIVITY BODY WITH THE INTERFACE METHODS ! **/
// Then call your AsyncTask where you want and pass it your context which implements the interface ( because you are in activity your context with the interface is "this"!
new YourTask(this).execute(params);
// Then inside your AsyncTask:
public class YourTask extends AsyncTask<String, Void, String> {
private IYourCallback mCallback;
public YourTask(Context context){
try{
mCallback = (IYourCallback) mCallback;
} catch(ClassCastException e){
onException(e); // Manage the exception and stop the operation
}
}
/** THEN IMPLEMENT YOU IN BACKGROUND... AND WHEN THE NETWORKING OPERATION IS FINISHED USE THE CALLBACK TO RETURN BACK YOUR RESULT, SO THE METHOD IN YOUR ACTIVITY WILL GET TRIGGERED AND YOU CAN CONTINUE TO DO YOUR OPERATIONS! So do: **/
if(success)
mCallback.onNetOperationSuccess(myListAnswer)
else
mCallback.onNetOperationError(error) // Throwable or exception
( Kotlin for the implementation of Retrofit! I started use Kotlin 5 days ago, so I don't know if this is the best use (: )
Example with Retrofit:
/* This is a RetrofitHelper which init the Retrofit instance and where you should put your networking methods. Then to do a networking operation you have to get this instance using (RetrofitHelper.getInstance().yourNetworkingOperation(...) ).
Anyway here there isn't the asynchronous part, you can get it in the link of my other comment below!
I don't have complete this class yet! */
class RetrofitHelper(baseUrl: String){
private val TAG = this.javaClass.name
// Timeouts
private val CONNECT_TIMEOUT = "CONNECT_TIMEOUT"
private val READ_TIMEOUT = "READ_TIMEOUT"
private val WRITE_TIMEOUT = "WRITE_TIMEOUT"
// Header Names
private val BASE_REQ_HEADER_NAME = "BLEDataBinder"
private val REQ_HEADER_NAME = "$BASE_REQ_HEADER_NAME.Request"
private val REQ_HEADER_VERSION_NAME = "$BASE_REQ_HEADER_NAME.VersionName"
private val REQ_HEADER_VERSION_CODE = "$BASE_REQ_HEADER_NAME.VersionCode"
private val REQ_HEADER_DEVICE_IMEI = "$BASE_REQ_HEADER_NAME.DeviceIMEI"
private val REQ_HEADER_DEVICE_UNIQUE_ID = "$BASE_REQ_HEADER_NAME.DeviceUniqueID"
private val REQ_HEADER_DEVICE_MODEL = "$BASE_REQ_HEADER_NAME.DeviceModel"
private val REQ_HEADER_ANDROID_RELEASE = "$BASE_REQ_HEADER_NAME.AndroidRelease"
// Header Values
private val REQ_HEADER_VALUE = "emax"
// Labels
private val LABEL_INIT = "Init RetrofitHelper"
private var mBaseUrl: String
private var mGson: Gson
private var mRetrofit: Retrofit
companion object {
#Volatile private var mInstance: RetrofitHelper? = null
fun getInstance() = mInstance
fun initInstance(baseUrl: String): RetrofitHelper =
mInstance ?: synchronized(this){
mInstance ?: newInstance(baseUrl).also { mInstance = it }
}
private fun newInstance(baseUrl: String) = RetrofitHelper(baseUrl)
}
init {
LogUtils.iLog(TAG, "START $LABEL_INIT")
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor( getInterceptor() )
httpClient.addInterceptor( getLoggingInterceptor() )
this.mBaseUrl = baseUrl
mGson = getGson()
mRetrofit = getRetrofit(httpClient.build())
LogUtils.iLog(TAG, "END $LABEL_INIT")
}
/* START Private Methods */
private fun getRetrofit(httpClient: OkHttpClient): Retrofit{
return Retrofit.Builder()
.baseUrl(mBaseUrl)
.addConverterFactory(GsonConverterFactory.create(mGson))
.client(httpClient)
.build()
}
private fun getGson(): Gson{
return GsonBuilder()
.setDateFormat(Constants.DATETIME_FORMAT_DB)
.registerTypeAdapter(Boolean::class.javaObjectType, BooleanDeserializer())
.create()
}
private fun getLoggingInterceptor() =
HttpLoggingInterceptor {
getLoggingInterceptorLogger()
}.also { it.level = HttpLoggingInterceptor.Level.BODY }
private fun getLoggingInterceptorLogger() =
HttpLoggingInterceptor.Logger {
message -> HyperLog.v(TAG, message)
}
private fun getInterceptor(): Interceptor =
Interceptor {
buildInterceptorResponse(it)
}
private fun buildInterceptorResponse(chain: Interceptor.Chain): Response {
val builder: Request.Builder = chain.request().newBuilder().addHeader(REQ_HEADER_NAME, REQ_HEADER_VALUE)
setRequestHeaderVersionName(builder)
setRequestHeaderVersionCode(builder)
setRequestHeaderDeviceIMEI(builder)
setRequestHeaderDeviceUniqueID(builder)
setRequestHeaderDeviceModel(builder)
setRequestHeaderAndroidRelease(builder)
/* This part let you set custom timeout for different api call inside the "RetrofitAPI" interface using that labels: (example inside the RetrofitAPI interface)
public interface RetrofitAPI {
#Headers({RetrofitHelper.CONNECT_TIMEOUT + ":100000", RetrofitHelper.READ_TIMEOUT + ":100000"})
#FormUrlEncoded
#POST
Call<JsonObject> doBaseJsonRequest(#Url String url, #Field("params") String params);
}
*/
var connectTimeout = chain.connectTimeoutMillis()
var readTimeout = chain.readTimeoutMillis()
var writeTimeout = chain.writeTimeoutMillis()
val request = chain.request()
if(!TextUtils.isEmpty(request.header(CONNECT_TIMEOUT))){
connectTimeout = request.header(CONNECT_TIMEOUT)!!.toInt()
}
if(!TextUtils.isEmpty(request.header(READ_TIMEOUT))){
readTimeout = request.header(READ_TIMEOUT)!!.toInt()
}
if(!TextUtils.isEmpty(request.header(WRITE_TIMEOUT))){
writeTimeout = request.header(WRITE_TIMEOUT)!!.toInt()
}
builder.removeHeader(CONNECT_TIMEOUT)
builder.removeHeader(READ_TIMEOUT)
builder.removeHeader(WRITE_TIMEOUT)
return chain
.withConnectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.withReadTimeout(readTimeout, TimeUnit.MILLISECONDS)
.withWriteTimeout(writeTimeout, TimeUnit.MILLISECONDS)
.proceed(builder.build())
}
/*private fun setRequestHeaders(builder: Request.Builder): Request.Builder{
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mVersionName)){
builder.addHeader(REQ_HEADER_VERSION_NAME, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mVersionCode.toString())){
builder.addHeader(REQ_HEADER_VERSION_CODE, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceIMEI)){
builder.addHeader(REQ_HEADER_DEVICE_IMEI, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceUniqueID)){
builder.addHeader(REQ_HEADER_DEVICE_UNIQUE_ID, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceModel)){
builder.addHeader(REQ_HEADER_DEVICE_MODEL, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mAndroidRelease)){
builder.addHeader(REQ_HEADER_ANDROID_RELEASE, AppEnvironment.getInstance()!!.mVersionName!!)
}
return builder
}*/
private fun setRequestHeaderVersionName(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mVersionName)){
builder.addHeader(REQ_HEADER_VERSION_NAME, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderVersionCode(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mVersionCode.toString())){
builder.addHeader(REQ_HEADER_VERSION_CODE, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderDeviceIMEI(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceIMEI)){
builder.addHeader(REQ_HEADER_DEVICE_IMEI, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderDeviceUniqueID(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceUniqueID)){
builder.addHeader(REQ_HEADER_DEVICE_UNIQUE_ID, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderDeviceModel(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceModel)){
builder.addHeader(REQ_HEADER_DEVICE_MODEL, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderAndroidRelease(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mAndroidRelease)){
builder.addHeader(REQ_HEADER_ANDROID_RELEASE, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
/* END Private Methods */
}
LINK TO MY COMMENT FOR ASYNC RETROFIT USAGE WITH GENERIC TYPES METHODS AND CALLBACK INTERFACES:
RETROFIT ASYNC WITH GENERIC TYPES
(This is in java but you can easily translate it in Kotlin! Also I suggest you to learn Java too because Kotlin is a scripting language built up Java so it translates the code in Java operations whose sometimes are really bigger (and sometimes slower) than if you wrote the code in Java! So, now I am learning Kotlin after learned Java for android applications, Kotlin is a really good, smart, beautiful and fast programming language for apps and I will use it to do fast and smart scripts inside my applications or for simple applications, but I will use Java too because with it you can generate faster code.
Hope this is helpful,
Bye and Good Coding! (:

Why am I suddenly unable to refresh idToken with Firebase REST API in an AS3 AIR Android Project.?

I have integrated Firebase Authentication and Storage using this guide and it was working just fine. Yesterday suddenly, I am unable to get to refresh the token. Every time I call the refreshToken(idToken) method, I get a 400:Invalid Id Token error.
I didn't change the code. I was testing the app one day and it was working fine, I checked that same app the next day and it wasn't working. I have no idea what to do. Any help is greatly appreciated.
Here is the code I am using to refresh the token:
private function refreshToken(idToken:String):void
{
trace("refreshing id token");
var header:URLRequestHeader = new URLRequestHeader("Content-Type", "application/json");
var myObject:Object = new Object();
myObject.grant_type = "authorization_code";
myObject.code = idToken;
var request:URLRequest = new URLRequest("https://securetoken.googleapis.com/v1/token?key="+FIREBASE_API_KEY);
request.method = URLRequestMethod.POST;
request.data = JSON.stringify(myObject);
request.requestHeaders.push(header);
var loader:URLLoader = new URLLoader();
loader.addEventListener(flash.events.Event.COMPLETE, refreshTokenLoaded);
loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
loader.load(request);
}
Firebase recently changed the way you get an access_token.
I have updated the guide to reflect the changes, you now need to add an extra parameter when logging in.
private function login(email:String, password:String):void
{
var myObject:Object = new Object();
myObject.email = email;
myObject.password = password;
myObject.returnSecureToken = true; <-- New parameter
var header:URLRequestHeader = new URLRequestHeader("Content-Type", "application/json");
var request:URLRequest = new URLRequest("https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key="+FIREBASE_API_KEY);
request.method = URLRequestMethod.POST;
request.data = JSON.stringify(myObject);
request.requestHeaders.push(header);
var loader:URLLoader = new URLLoader();
loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
loader.addEventListener(flash.events.Event.COMPLETE, signInComplete);
loader.load(request);
}
In the response you will now get a refreshToken, you must exchange it for an access token with the following function:
private function refreshToken(refreshToken:String):void
{
var header:URLRequestHeader = new URLRequestHeader("Content-Type", "application/json");
var myObject:Object = new Object();
myObject.grant_type = "refresh_token";
myObject.refresh_token = refreshToken;
var request:URLRequest = new URLRequest("https://securetoken.googleapis.com/v1/token?key="+FIREBASE_API_KEY);
request.method = URLRequestMethod.POST;
request.data = JSON.stringify(myObject);
request.requestHeaders.push(header);
var loader:URLLoader = new URLLoader();
loader.addEventListener(flash.events.Event.COMPLETE, refreshTokenLoaded);
loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
loader.load(request);
}

set DeviceToken in parse for Android

i can't set the device token in Installation table using parse
im using
ParseInstallation installation =ParseInstallation.getCurrentInstallation();
installation.put("GCMSenderId",senderId);
installation.put("pushType","gcm");
installation.put("deviceToken",token);
but when i try to use save i got an exception.
Cannot modify `deviceToken` property of an _Installation object. android
The problem is, the backend use this tokenId to send the push notification for another provider (OneSignal), so im wondering if its any way to write in the deviceToken row (As far as i know this is for iOS only).
i need write in the deviceToke the GCM token i receive.
Thanks
I solved this by adding a Parse Cloud function called setDeviceToken. This way I can use the MasterKey to modify the Installation record.
Parse.Cloud.define("setDeviceToken", function(request, response) {
var installationId = request.params.installationId;
var deviceToken = request.params.deviceToken;
var query = new Parse.Query(Parse.Installation);
query.get(installationId, {useMasterKey: true}).then(function(installation) {
console.log(installation);
installation.set("deviceToken", deviceToken);
installation.save(null, {useMasterKey: true}).then(function() {
response.success(true);
}, function(error) {
response.error(error);
})
}, function (error) {
console.log(error);
})
});
Then, in my Android app's Application.onCreate:
OneSignal.idsAvailable(new OneSignal.IdsAvailableHandler() {
#Override
public void idsAvailable(String userId, String registrationId) {
final ParseInstallation currentInstallation = ParseInstallation.getCurrentInstallation();
if (registrationId != null) {
HashMap<String, Object> params = new HashMap<>(2);
params.put("installationId", currentInstallation.getObjectId());
params.put("deviceToken", registrationId);
ParseCloud.callFunctionInBackground("setDeviceToken", params, new FunctionCallback<Boolean>() {
#Override
public void done(java.lang.Boolean success, ParseException e) {
if (e != null) {
// logException(e);
}
}
});
}
}
});
For future visitors, I solved this a different way, by using the Parse Rest API: http://parseplatform.org/docs/rest/guide/
Using that, you can bypass the regular SDK limitations. Just make a put request to https://yourApp/parse/installtions/{installationObjectIDHere}. make a dictionary and encode it as JSON:
Map<String, String> dictionary = new HashMap<String, String>();
dictionary.put("deviceToken", yourToken);
JSONObject jsonDictionary = new JSONObject(dictionary);
String bodyAsString = jsonDictionary.toString();
RequestBody body = RequestBody.create(JSON, bodyAsString);
then send the request, and that should work.
joey showed the right way to do that, the extra part i added is about the authentication header.
This is what i did:
val JSON = MediaType.parse("application/json; charset=utf-8")
val client = OkHttpClient()
val installationObjectId = ParseInstallation.getCurrentInstallation().objectId
val myAppId = getString(R.string.parse_app_id)
val key = getString(R.string.parse_client_key)
val server = getString(R.string.parse_server_url)
val mRequestUrl = "$server/installations/$installationObjectId"
val dictionary = HashMap<String, String?>()
dictionary["deviceToken"] = myToken
val jsonDictionary = JSONObject(dictionary)
val bodyAsString = jsonDictionary.toString()
val body = RequestBody.create(JSON, bodyAsString)
val request = Request.Builder()
.url(mRequestUrl)
.put(body)
.addHeader("X-Parse-Application-Id", myAppId)
.addHeader("X-Parse-Client-Key", key)
.build()
client.newCall(request).execute()

Is it possible to set placeholder path params with OkHttp

I have an url http://example.com/{x}/push/{y} and I'm using OkHttp curl it.
final HttpUrl httpUrl = HttpUrl
.parse("http://example.com/{x}/push/{y}")
.newBuilder()
???
.build();
Is it possible to set these {x} and {y} path params?
I can see method like addPathSegment which is somehow related, but not what I want.
Here’s one technique that might help you to get started.
HttpUrl template = HttpUrl.parse("http://example.com/{a}/b/{c}");
HttpUrl.Builder builder = template.newBuilder();
for (int i = 0; i < template.pathSegments().size(); i++) {
String parameter = template.pathSegments().get(i);
String replacement = null;
if (parameter.equals("{a}")) {
replacement = "foo";
} else if (parameter.equals("{c}")) {
replacement = "bar";
}
if (replacement != null) {
builder.setPathSegment(i, replacement);
}
}
HttpUrl url = builder.build();
Maybe HttpUrl.setPathSegment(index, value) can make it look a bit better :D
fun HttpUrl.insertPathSegment(index: Int, pathSegment: String): HttpUrl {
val newPathSegments: ArrayList<String> =
encodedPathSegments().fold(ArrayList()) { acc, oldPathSegment ->
printLog("OkHttp", "insertPathSegment oldPathSegment:$oldPathSegment ")
acc.add(oldPathSegment)
acc
}
return newBuilder().apply {
try {
newPathSegments.add(index, pathSegment)
addEncodedPathSegment("")
newPathSegments.forEachIndexed { index, path ->
printLog("OkHttp", "insertPathSegment setEncodedPathSegment:$index $path ")
setEncodedPathSegment(index, path)
//printLog("OkHttp", "insertPathSegment setPathSegment:$index $path ")
//setPathSegment(index, path)
}
} catch (e: Exception) {
e.printStackTrace()
}
}.build()}
I used the following approach to pass path variables:
inputUrl= http://localhost:8080/getResults/firstName/%s/lastName/%s
HttpUrl url = HttpUrl.get(String.format(inputUrl, "fn","ln"));
Request request = new Request.Builder().url(url).build();

Categories

Resources