How to access metadata from AndroidManifest.xml in Xamarin.Froms - c#

I'm trying to access metadata from AndroidManifest.xml in Xamarin.Forms Android project.
I have this code:
var ai = CrossCurrentActivity.Current.Activity.PackageManager
.GetApplicationInfo(CrossCurrentActivity.Current.Activity.PackageName,
PackageInfoFlags.MetaData);
var meta = ai.MetaData;
Problem is, that ai.Metadata is NULL. Any idea what is wrong?
Thanks.
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="com.my.test.x2.x8" android:versionName="15.0" android:versionCode="15">
<uses-sdk android:minSdkVersion="15" />
<application android:label="MyApp" android:icon="#drawable/Icon"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application>
<meta-data android:name="MYENDPOINT" android:value="https://xxx.azurewebsites.net/" />
</application>
</manifest>

Place your meta-data inside your existing application span and remove the other one, i.e.:
Example:
<application android:label="MyApp" android:icon="#drawable/Icon">
<meta-data android:name="MYENDPOINT" android:value="https://xxx.azurewebsites.net/" />
</application>
Usage:
var bundle = PackageManager.GetApplicationInfo(PackageName, Android.Content.PM.PackageInfoFlags.MetaData).MetaData;
foreach (var key in bundle.KeySet())
{
Log.Debug("SO", $"{key} : {bundle.GetString(key)}");
}
Output:
08-03 09:18:56.642 3519 3519 D SO : MYENDPOINT : https://xxx.azurewebsites.net

Related

resource xml/provider_paths (aka com.BQProject.betterquestx:xml/provider_paths) not found

Sorry, I have some problems in my Xamarin Forms aplication, I am trying to trigger the installation of the application using this code:
public void LetsInstall(string filepath)
{
Java.IO.File file = new Java.IO.File(filepath);
Context context = Android.App.Application.Context;
Android.Net.Uri path = FileProvider.GetUriForFile(context, context.PackageName + ".provider", file);
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
Android.Net.Uri URIAPK = FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".provider", (Java.IO.File)filepath);
Intent intS = new Intent(Intent.ActionView);
intS.SetData(URIAPK);
intS.SetFlags(ActivityFlags.GrantReadUriPermission);
Android.App.Application.Context.StartActivity(intS);
}
else
{
Android.Net.Uri URIAPK = Android.Net.Uri.FromFile((Java.IO.File)filepath);
Intent intS = new Intent(Intent.ActionView);
intS.SetDataAndType(URIAPK, "application/vnd.android.package-archive");
intS.SetFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intS);
}
}
But it doesn't work out for me. A Java.Lang.IllegalArgumentException: 'Couldn't find meta-data for provider with authority com.BQproject.betterquestx.provider' error occurs on line 5
I tried to register this code in AndroidManifest:
<?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.BQProject.betterquestx" android:installLocation="auto">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="31" />
<application android:label="BetterQuestX.Android" android:theme="#style/MainTheme" android:icon="#drawable/icon_about">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
I also created Resources/xml/provider_paths and added code to it:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
</paths>
As a result, the resource xml/provider_paths (aka com.BQProject.betterquestx:xml/provider_paths) not found. This error is likely caused by an issue with the AndroidManifest.xml file or an Android manifest generation attribute in a source code file error appeared and I do not know what to do with it, please help

Xamarin Forms Android Ad-Hoc apk update There was a problem parsing the package

Trying to create an android autoupdater for an ahoc app in Xamarin forms.
here is my code and manifest and paths xml.
The app launches fine and i can get the updater dialog. it then seems to download the apk but when it comes to install it i get the 'There was a problem parsing the package' error.
I have tried loads of different ways to do this so some pointers would be cool.
i also tried to look in logcat in release and its saying file permission error but im not sure if this is a red herring or not.
Anyone got any ideas?
```
public async void LaunchActivityInAndroid()
{
string documentsPath = $"{Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath}";
string m_uri = $"{GlobalVariables.ApkPrefix}{GlobalVariables.ApkDomain}{GlobalVariables.ApkEndpoint}";
string fileName = m_uri.Substring(m_uri.LastIndexOf("/") + 1);
HttpResponseMessage httpResponse = await new HttpClient().GetAsync(m_uri);
byte[] data = await httpResponse.Content.ReadAsByteArrayAsync();
string directory = Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath.ToString();
string path = Path.Combine(directory, fileName);
foreach (string file in Directory.GetFiles(directory))
{
if (Path.GetExtension(file) == ".apk")
{
File.Delete(file);
File.Delete("app.db3");
}
}
File.WriteAllBytes(path, data);
Android.Net.Uri fileUri;
if ((int)Build.VERSION.SdkInt < 23) {
fileUri = Android.Net.Uri.FromFile(new Java.IO.File(path));
}
else {
fileUri = FileProvider.GetUriForFile(Xamarin.Forms.Forms.Context as Context, Xamarin.Forms.Forms.Context.ApplicationContext.PackageName + ".fileprovider", new Java.IO.File(documentsPath + "/app.apk"));
}
Intent promptInstall = new Intent(Intent.ActionView).SetFlags(ActivityFlags.ClearTop).SetFlags(ActivityFlags.GrantReadUriPermission).SetFlags(ActivityFlags.NewTask).PutExtra(Intent.ExtraNotUnknownSource, true).SetDataAndType(fileUri, "application/vnd.android.package-archive");
Android.App.Application.Context.StartActivity(promptInstall);
//webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
}
'''
Manifest
```
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.99" package="app" android:installLocation="auto" android:versionCode="1">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="29" />
<application android:label="app.Android" android:icon="#mipmap/ic_launcher" android:networkSecurityConfig="#xml/network_security_config" android:allowBackup="false" android:requestLegacyExternalStorage="true">
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/provider_paths"></meta-data>
</provider>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.WRITE_PROFILE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
</manifest>
```
provider paths xml
```
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
```
Thanks in advance guys!

How to get provider authorities value from an Android manifest file programmatically in Xamarin Forms?

I'm developing an Android with Xamarin.Forms, and I'm using the AndroidManifest.xml file shown below.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="26" android:targetSdkVersion="26" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application android:label="MyApp.Android">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="myapp.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_file_paths" />
</provider>
</application>
I'd like to get the android:authorities value of the provider directive (in my case "myapp.fileprovider" as string) programmatically.
How is this possible with Xamarin.Forms?
I found an answer.
var context = Android.App.Application.Context;
var component = new Android.Content.ComponentName(context, Java.Lang.Class.FromType(typeof(Android.Support.V4.Content.FileProvider)));
var info = context.PackageManager.GetProviderInfo(component, Android.Content.PM.PackageInfoFlags.MetaData);
var authority = info.Authority;
Kotlin version as a helper function
fun getFileProviderAuthorities(context: Context): String {
val component = ComponentName(context, FileProvider::class.java)
val info = context.packageManager.getProviderInfo(component, android.content.pm.PackageManager.GET_META_DATA)
return info.authority
}

AndroidRuntime Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.multidex.MultiDexApplication"

I have an issue with launching my app in Release mode.
I have enabled MultiDex for Debug and Release modes. When deploying in Debug mode, my app is working fine and everything OK. But when I launch it Release mode, it crashes at startup. Here's a Device Log:
Android manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionName="17.2" android:versionCode="1"
android:installLocation="auto" package="com.myapp">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application android:label="Test Application" android:largeHeap="true" android:icon="#drawable/AppIcon" android:supportsRtl="true">
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/provider_paths" />
</provider>
</application>
</manifest>
Make your Application extend MultiDexApplication. If you don't have one already just create a BaseApplication class like so:
public class BaseApplication extends MultiDexApplication {
#Override
public void onCreate() {
super.onCreate();
}
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
also, add the following to your build.gradle:
multiDexEnabled true
for your dependencies:
dependencies {
implementation 'androidx.multidex:multidex:2.0.1'
}
or if not using AndroidX
dependencies {
implementation 'com.android.support:multidex:1.0.3'
}
Finally in your manifest add within your application tag:
android:name="android.support.multidex.MultiDexApplication"
or
android:name="androidx.multidex.MultiDexApplication"
if you've migrated to AndroidX

Xamarin Forms File Provider not set

I am currently going through the process of Learning Xamarin.Forms. I am currently attempting to implement Camera functions using the Plugin.Media.CrossMedia library.
Implemented below:
public async Task<ImageSource> StartCamera()
{
await CrossMedia.Current.Initialize();
if (Plugin.Media.CrossMedia.Current.IsTakePhotoSupported && CrossMedia.Current.IsCameraAvailable)
{
var photo = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions() { SaveToAlbum=false, SaveMetaData=false});
if (photo != null)
return ImageSource.FromStream(() => { return photo.GetStream(); });
else
return null;
}
else
{
return null;
}
}
However upon executing the 'TakePhotoAsync' method I recieve the following error.
System.ArgumentException: Unable to get file location. This most likely means that the file provider information is not set in your Android Manifest file. Please check documentation on how to set this up in your project.
I have tried looking this up but to no avail. My AndroidManifest.xml file looks like this at the moment.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="RCPTTracker.Android" android:versionCode="1" android:versionName="1.0">
<uses-sdk />
<application android:label="RCPTTracker.Android"></application>
</manifest>
My inkling is that I need to declare something in here, but I haven't been able to find what, and all tutorials i have followed don't go through anything with setting up a File Provider.
Any suggestions?
The readme says:
If your application targets Android N (API 24) or newer, you must use version 2.6.0+.
You must also add a few additional configuration files to adhere to the new strict mode:
1.) Add the following to your AndroidManifest.xml inside the tags:
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="YOUR_APP_PACKAGE_NAME.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
YOUR_APP_PACKAGE_NAME must be set to your app package name!
2.) Add a new folder called xml into your Resources folder and add a new XML file called file_paths.xml
Add the following code:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
<external-files-path name="my_movies" path="Movies" />
</paths>
YOUR_APP_PACKAGE_NAME must be set to your app package name!
You can read more at: https://developer.android.com/training/camera/photobasics.html
In my case it was because I had put the FileProvider in the wrong place in the AndroidManifest.xml file. It needed to be inside the <Application> tags.
<?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.myapp.app1" android:installLocation="auto">
<uses-sdk android:minSdkVersion="22" android:targetSdkVersion="27" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BROADCAST_WAP_PUSH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<application android:label="app1.Android">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyCZF1O9_7-MXlxYfAEIxBQkr-dR8RiwiYE" />
<!-- ADD FILE PROVIDER HERE -->
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="com.myapp.app1.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
</application>
</manifest>
The problem I had was related to case-sensitivity.
On the line below
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="com.myexample.myapp.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
I erroneously had a single uppercase letter on the line android:authorities="com.myexample.myapp.fileProvider". It should be:
android:authorities="com.myexample.myapp.fileprovider" <!-- all lowercase -->
Or
android:authorities="${applicationId}.fileprovider"
The package name and value for android:authorities should be lowercase. Otherwise you will get the error:
System.ArgumentException: Unable to get file location. This most
likely means that the file provider information is not set in your
Android Manifest file. Please check documentation on how to set this
up in your project.
Make sure you only have one set of <application> tags
I was stuck on this error for literally weeks... Then I realised I had duplicate application tags.
defined once like this:
<application android:label="App2.Android"></application>
the second set of <application> tags had the correct configuration lower down, but were being ignored. Removing the empty tags solved the issue for me.
Marco's solution is almost right. For it to work in my project I had to change
android:authorities="YOUR_APP_PACKAGE_NAME.fileprovider"
to
android:authorities="${applicationId}.fileprovider"
in the AndroidManifest.xml file.
Above answers resolved this issue for me. Here's what my AndroidManifest.xml looks like (using ${applicationId} for the authorities tag helps because sometimes you just don't know exactly how your app name is):
<?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.companyname.app2">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application android:label="App2.Android" android:theme="#style/MainTheme">
<provider android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
</application>
</manifest>
<provider android:name="androidx.core.content.FileProvider"
android:authorities="APP_PACKAGE_NAME.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
Xml must be in under xml folder
With the latest version, correct XML configuration is (without adding the package name to the path)
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
<external-files-path name="my_movies" path="Movies" />
</paths>
If you set path combining the package name like below
<external-path name="my_images" path="Android/data/YOUR_APP_PACKAGE_NAME/files/Pictures" />
It may give this type of error.
Android Support Libraries are now in the androidx.* package hierarchy instead of android.support.
So use following provider tag in you application's manifest.xml file.
<provider android:name="androidx.core.content.FileProvider"
android:authorities="YOUR_APP_PACKAGE_NAME.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data></provider>
It must be under application tag.
In addition to these things I had to do one more thing to get rid of this error. I had manually added the xml folder and file_paths.xml into the project folder. However, I had not yet added them to the project in the solution. Once I right clicked on the Resources folder and added New Folder (xml) and Existing Item (file_paths.xml) the error went away.

Categories

Resources