.net Maui - basic web request - android

Ive been playing with .net Maui and had some success doing Bluetooth LE but for reasons I've gone ahead and changed my implementation to use wifi and a restful API. I am building for both android and IoS. I am testing with a real device, running android 12.
I am trying to make a basic http(s) (tried both http and https) request to a local server (an esp32). My url is:
const string url = "https://192.168.4.1/api";
My manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="31" />
<application android:allowBackup="true" android:icon="#mipmap/appicon" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
My initialisation function, which gets called when my page is loaded - MainPage()
private void init_network()
{
client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
}
and finally, my send function which gets called by a button pressed event
private bool SendCommand(string command)
{
try
{
var msg = new HttpRequestMessage(HttpMethod.Post, url);
msg.Content = JsonContent.Create(command);
HttpResponseMessage response = client.Send(msg); // line where the code throws exception
if (response.IsSuccessStatusCode)
{
return true;
}
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
return false;
}
I also have a runtime permissions section which asks for location_fine_access, which I've given access for.
When running through the request function, I get an exception thrown with the message:
[DOTNET] Operation is not supported on this platform.
I thought this was a permissions issue, and so android isn't letting me make the request but now I'm not so sure. Anyone else had and resolved this issue?

Looks as though .net maui doesnt hook into the android http client properly and is an issue on github. https://github.com/dotnet/maui/issues/1260
the suggested work around, which I have tested and works for me, is to instantiate your HttpClient with the native android handler like this as a workaround:
new HttpClient(new Xamarin.Android.Net.AndroidMessageHandler()).

Related

Amazon IAP Delegate not executed in Xamarin (Listener doesn't work?)

I'm trying to implement Amazon IAP in a xamarin project following the documentation here.
So here's how my manifest looks like:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="87" android:versionName="8.7" package="XXXXXXXXXXXX">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
<application android:icon="#mipmap/ic_launcher" android:label="XXXXXXXXXXXX">
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="XXXXXXXXXXXX" />
<receiver android:name="com.amazon.device.iap.ResponseReceiver" android:permission="com.amazon.inapp.purchasing.Permission.NOTIFY" >
<intent-filter>
<action android:name="com.amazon.inapp.purchasing.NOTIFY" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
And here's my code which is in the Android Project of my solution:
public async Task<bool> MyMethod()
{
try
{
var iapService = AmazonIapV2Impl.Instance;
var tcs = new TaskCompletionSource<bool>();
var skus = new SkusInput { Skus = new List<string>() { "XXXXXXXXX" } };
var requestId = iapService.GetProductData(skus).RequestId;
GetProductDataResponseDelegator delegator = null;
delegator = new GetProductDataResponseDelegator(async response =>
{
await Task.Run(() =>
{
DoSomething();
tcs.SetResult(result);
});
});
iapService.AddGetProductDataResponseListener(delegator.responseDelegate);
await tcs.Task;
}
catch(Exception ex)
{
}
return true;
}
This doesn't throw exceptions but the method DoSomething(); is never called and the last line return true; is never reached. Also the line tcs.Task is stuck on WaitingActivation status. It's like the listener/reciever wasn't working. So my code endlessly wait for the answer.
Any idea how to fix this?
I'm using Xamarin Form version: 5.0.0
Running on Mac, through Visual Studio and debugging on a simulator or a real device (Xiaomi mi9)
Thanks
So first of all the code await Task.Run(() => wasn't necessary to make it work. Secondly, the problem was that my app wasn't submitted yet on the Amazon AppStore and so to test a non-submit app you need to download on your testing phone the app:Amazon App Tester.
In case you have issue to download the Amazon App Tester read this:
In the past, I've tried to download the Amazon App Tester but for some reason my phone didn't want it. I finally "bought" it (it's $0.00 anyway) from my computer on amazon website. Once bought, I was able to find the app in the tab "my app" in the Amazon AppStore on my phone.

Connect Android app to local Laravel database [duplicate]

This question already has answers here:
How do you connect localhost in the Android emulator? [duplicate]
(7 answers)
Closed 1 year ago.
first of all I'd like to say that I've been looking for answers in a lot of places, but I just can't seem to find any that work for me. At the end I'll list all the options I've tried already. I'm new to Android and this is driving me nuts.
What I'm trying to do is submit a simple GET request to a local Laravel database running on my Mac. I'm trying to call this request from an Android app on an emulator.
My Laravel server is running on 127.0.0.1:8000 and it is turned on. In the .env file it states that DB_PORT=3306, but when changing the port in the request it doesn't matter.
What I'm doing in Android:
String url = "http://127.0.0.1:8000/api/recipes"; // More on the IP at the end
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("heeftGewerkt", response.substring(30));
errorMessage = "Succesful register";
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("heeftNietGewerkt", error.getMessage());
errorMessage = "Unsuccesful register";
}
});
My androidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.a1114049_1090780_iiatimd_app">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="#style/Theme.1114049_1090780_iiatimd_app">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I understand that when sending a request to 127.0.0.1 it might look for a server on the android device, which it obviously can't find. So I've tried to replace 127.0.0.1:8000 with localhost:8000, local-ip:8000 and public-ip:8000. None of these seem to work.
When I make a request to the Laravel server using Postman (http://127.0.0.1:8000/api/recipes) it works and I get all the recipes in my database. Can anyone clear this up for me?
EDIT:
The error I get is 'Failed to connect to /127.0.0.1:8000'. Looking at this it might be because I'm not passing in any DB credentials anywhere, but I'm also not sure if I should.
Use 10.0.2.2 to access your actual machine instead of localhost/127.0.0.1
When inside the emulator local host is referring to the emulator itself. However the emulator supports forwarding to the host machine on ip address 10.0.2.2
So you db server address with be
10.0.2.2:8000

Azure Authentication with AAD & Google in a Xamarin Forms Project not Redirecting back to app after Authorized

Azure Active Directory
Google+ Auth
Xamarin Forms, PCL (NuGet 2.4.0.282)
Microsoft.Azure.Mobile.Client 4.0.0 & 4.0.2
After I successfully Login my phone does not return to my app. I have two test phones and one emulator, they display different info, after login.
Phone 1 (AAD Auth):
Phone 1 (Google Auth it greys out and just keeps "loading")
Phone 2 (AAD and Google Auth):
Emulator (AAD and Google Auth):
I have done everything I found here on Stack OverFlow, that makes sense and seems to be applicable to current versions of NuGets.
This person seems to be having a similar issue to me but with Google Log in
Azure not redirecting after loginenter link description here
I have tried integrating code into my project. And then I input my Azure info into Xamarin's sample: https://github.com/xamarin/xamarin-forms-samples/tree/master/WebServices/TodoAzureAuth
And I get the same results. I have tried both AAD and Google+ Auth. After login it just stays at the browser. So I feel like the client side code has to be correct. But I cant find any mess up on my Azure server code. I have tried this with projects that have a C# and Node.Js backend.(For one of my projects) My ALLOWED EXTERNAL REDIRECT URLS is ToDoList53172://easyauth.callback and in my AndroidManifest.xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.xamarin.sample.TodoAzure">
<uses-sdk android:minSdkVersion="15" />
<application android:label="TodoAzure" android:icon="#drawable/icon">
<activity android:name="com.microsoft.windowsazure.mobileservices.authentication.RedirectUrlActivity" android:launchMode="singleTop" android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="ToDoList53172" android:host="easyauth.callback" />
</intent-filter>
</activity>
</application>
</manifest>
OLD:
And I don't feel like I should post all the other code. It is all in the Xamarin sample project posted above. If people think I should I will.
NEW:
I am adding more code just to help people out. I did not want to overload, but better to have all the info in one place. So here is my MainActivity.cs Code
using System;
using System.Threading.Tasks;
using Android.App;
using Android.Content.PM;
using Android.OS;
using Microsoft.WindowsAzure.MobileServices;
using Android.Webkit;
namespace TodoAzure.Droid
{
[Activity(Label = "TodoAzure.Droid",
Icon = "#drawable/icon",
MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
Theme = "#android:style/Theme.Holo.Light")]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity, IAuthenticate
{
MobileServiceUser user;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init();
App.Init((IAuthenticate)this);
LoadApplication(new App());
}
public async Task<bool> AuthenticateAsync()
{
bool success = false;
try
{
if (user == null)
{
// The authentication provider could also be Facebook, Twitter, or Microsoft
user = await TodoItemManager.DefaultManager.CurrentClient.LoginAsync(this, MobileServiceAuthenticationProvider.Google, Constants.URLScheme);
if (user != null)
{
CreateAndShowDialog(string.Format("You are now logged in - {0}", user.UserId), "Logged in!");
}
}
success = true;
}
catch (Exception ex)
{
CreateAndShowDialog(ex.Message, "Authentication failed");
}
return success;
}
public async Task<bool> LogoutAsync()
{
bool success = false;
try
{
if (user != null)
{
CookieManager.Instance.RemoveAllCookie();
await TodoItemManager.DefaultManager.CurrentClient.LogoutAsync();
CreateAndShowDialog(string.Format("You are now logged out - {0}", user.UserId), "Logged out!");
}
user = null;
success = true;
}
catch (Exception ex)
{
CreateAndShowDialog(ex.Message, "Logout failed");
}
return success;
}
void CreateAndShowDialog(string message, string title)
{
var builder = new AlertDialog.Builder(this);
builder.SetMessage(message);
builder.SetTitle(title);
builder.SetNeutralButton("OK", (sender, args) => { });
builder.Create().Show();
}
}
}
And Like I said above I have tried this with AAD as well. The code above is for Google.
Here is my Azure Auth setup
Here is the info I get after logging in with "https://todolistjbb.azurewebsites.net/.auth/login/aad" and then visiting
"https://todolistjbb.azurewebsites.net/.auth/me"
I feel like I have tried SO many things. I have recorded 66.68 hours working on just trying to get Authentication in my app.... please... someone tell me what I am doing wrong! I am losing it over here :'(
The way to solve this problem is do not start with a capitalized letter for your Url Scheme. It took me over 2 weeks to figure it out. I don't think this sis written anywhere, but I am sure it is.
So yeah to fix this i switched "ToDoList53172" to "todolist53172"
That's it... Oy vey!
According to your description, I assumed that you are using the Server-managed authentication provided by Azure App Service authentication/authorization. Since you are using the Microsoft.Azure.Mobile.Client >= 4.0.0, for your mobile client, you would leverage the following code snippet for logging via the server-flow:
var user = await client.LoginAsync(this, provider, "{url_scheme_of_your_app}");
Details you could follow Add authentication to the app. Moreover, you need to Add your app to the Allowed External Redirect URLs.
Based on the error message from your phone 2:
todolistjbbservice://easyauth.callback/#authorization_code=xxxxx
It seems that you did not configured the Authorized Redirect URI correctly. For the Azure Active Directory provider, you could follow here for registering your Web App / API or Native application. For the Google provider, you could follow here.
After correctly configured your preferred identity provider(s), you need to add your app to the Allowed External Redirect URLs:
Log into Azure Portal, choose your App Service
Click the Authentication / Authorization,
enter ToDoList53172://easyauth.callback in the Allowed External Redirect URLs, and save your changes.

PhoneGap - Ajax XmlHttpequest work on emulator | desktop browser but not on device

I'm developing an app on PhoneGap (Cordova Apache) which make an Jquery Ajax XmlHttpRequest cross-domain request to my server.
Here is the code :
/*
* Create the XMLHttpRequest instance
*/
function getXDomainRequest() {
var xdr = null;
if (window.XDomainRequest) {
xdr = new XDomainRequest();
} else if (window.XMLHttpRequest) {
xdr = new XMLHttpRequest();
} else {
alert("Votre navigateur ne gère pas l'AJAX cross-domain !");
}
return xdr;
}
/*
* Load the data from menu into XMLHttpRequest and call create menu
*/
function sendData() {
var xdr = getXDomainRequest();
xdr.onload = function() {
var dcat = $.parseJSON(xdr.responseText);
createMenu(menu, dcat);
configureMenuScript();
}
xdr.open("GET", "http://preview.********.com/api/ApiProductList");
xdr.send();
}
sendData();
Its working fine on Firefox 28, IE 11 and Chrome 34. It also work fine on the android emulator with an AVD android 4.0.
In the Manifest.xml file I put the following data
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
And in the Config.xml
<param name="android-package" value="org.apache.cordova.core.NetworkManager" />
<access origin="*" />
I'm also allowing the cors in the above JS script
$.support.cors = true;
$.mobile.allowCrossDomainPages = true;
This should allow the Cross-Domain.
-> The issue is that it doesn't work on my device. (Android 4.2.2) I mean, the app load well, but when it come to display the data out of the ajax request, it doesn't work anymore.
Maybe I'm missing an authorization in the manifest or the config file ?
Unfortunately I can't debug live on the device :s
Thanks in advance !
nb: Windows 8.1 - PhoneGap Cordova Apache 3.4
I found out my problem. It was actually not due to an code error but due to the firewall of the company.
So, basically, the code above is working. At least it is a great recap on how to implement a XMLHttpRequest on phonegap :)

Android Connect Exception

i get a strange error message when i try to start an url connection.
here´s the log output:
E/admarvelservice( 2366): postString: &site_id=14488&partner_id=ef8a30b841b36346& timeout=5000&version=1.5&language=java&format=android&sdk_version=2.1.3&sdk_version_date=2011-08-08&device_model=Nexus+S&device_name=GRJ22&get_cached_ads=true&device_systemversion=2.3.5&resolution_width=480&max_image_width=480&resolution_height=800&max_image_height=800&device_os=Android&target_params=appv%3D%3ES%7C%7Cla%3D%3Ede%7C%7Cco%3D%3EAT%7C%7Cscreenorient%3D%3Ep%7C%7Cappvn%3D%3E3.4.0%252F%7C%7Cosv%3D%3E2.3.5
D/admarvelservice( 2366): Error: java.net.ConnectException: ads.admarvel.com/127.0.0.1:80 - Connection refused
anybody an idea whats the problem here?
thanks.
EDIT: how i connect:
URL myURL;
try {
myURL = new URL(_url);
m_ucon = myURL.openConnection();
m_ucon.setConnectTimeout(8000);
} catch (Exception e) {
e.printStackTrace();
}
funny thing is that the connection is working, but every second my logcat shouts the errormessage shown above.
I think this has nothing to do with your application.
The exception comes from an Advertising Service (admarvelservice).
You are using an adblocker app and you have Shazam installed. Just either get the paid version of Shazam, remove ad blocker or just ignore the error.
Check this first in your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Localhost ip address is: 127.0.0.1 so u can check by this too.
try with this http connection:
public SomeClass {
HTTTPUrlConnection conn = new HTTPUrlConnection(...);
SomeClass instance = new SomeClass();
private SomeClass() {}
public static getInstance() {
return instance;
}
}
you should try Singleton pattern for request response.
You must set uses permission in the AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
For my experience
Connection Refused
is caused by :
a|- You don´t have access because probably you are under a Proxy and you need credentials to establish a connection.
b|- You need to add the persmission for connection inside your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />

Categories

Resources