MAUI :System.UnauthorizedAccessException: Access to the path is denied - android

I'm making a new cross-platform MAUI App,and I tried to simply create a json file.the source code looks like this:
private async void WriteSomething()
{
#if ANDROID
FileStream fs = new(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) + "/test.json", FileMode.Create);
StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
await sw.WriteAsync(str);
sw.Close();
fs.Close();
#elif WINDOWS
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\test.json";
FileStream fs = new(path, FileMode.Create);
StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
await sw.WriteAsync(str);
sw.Close();
fs.Close();
#endif
}
The program runs well on windows machine,but the program throws System.UnauthorizedAccessException on android emulator.
I've searched this problem on StackOverflow,but most of the questions about this is on Xamarin platform.(Xamarin.Android or Xamarin.Forms)
According to the answers,I should request the storage permission like this:
First,add the following code to my AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Second,check if the target android version is Android M or above.If the answer is true,then invoke RequestPermissions method:
#if ANDROID
private void CheckAppPermissions()
{
if ((int)Build.VERSION.SdkInt < 23)
{
return;
}
else
{
if (PackageManager.CheckPermission(Manifest.Permission.ReadExternalStorage, PackageName) != Permission.Granted
&& PackageManager.CheckPermission(Manifest.Permission.WriteExternalStorage, PackageName) != Permission.Granted)
{
var permissions = new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage };
RequestPermissions(permissions, 1);
}
}
}
#endif
However,I found there is no such method in Android namespace.
CS0103 the name "RequestPermissions" does not exist in the current
context.
I guess it exists only in Xamarin platform.Or it acctually exists in another namespace.And that means I can't get the read and write permission I need.
A brand-new solution of the permission problem is needed.
**Note:**My English is poor.And I have little programming experience.Please forgive me.
Thanks in advance.

Actually, if you just operate the file in the System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) path, it shouldn't need any storage permissions. Because it's the app's own private folder. And I have tested your code in a new project, the josn file was created successfully.
In addition, if you want to request the permission in the maui, you need to use the api in the maui. You can use the following code instead of the yours.
PermissionStatus statusread = await Permissions.RequestAsync<Permissions.StorageRead>();
PermissionStatus statuswrite = await Permissions.RequestAsync<Permissions.StorageWrite>();
Finally, you can also use the permission Mahesh mentioned, but it should be used if necessary. And if you still want to it, you can try to add the following code in the MainActivity to grant the permission by the user.
protected override void OnCreate(Bundle savedInstanceState)
{
if (!Android.OS.Environment.IsExternalStorageManager)
{
Intent intent = new Intent();
intent.SetAction(Android.Provider.Settings.ActionManageAppAllFilesAccessPermission);
Android.Net.Uri uri = Android.Net.Uri.FromParts("package", this.PackageName, null);
intent.SetData(uri);
StartActivity(intent);
}
base.OnCreate(savedInstanceState);
}

use this permission, hope it's helps, check once with give manually permission.
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

Related

How do I read a deployed file in MAUI/Xamarin on Android

I have a small MAUI app i'm testing with. Im trying to read a file that was part of the deployment. I have the code below, which works great in a Windows deploy of the MAUI app, but crashes in Android. What is the proper cross-platform way to do this?
// TODO get from service or xml
var path = AppDomain.CurrentDomain.BaseDirectory;
//var path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
var fullpath = Path.Combine(path, "Services\\questions.json");
var json = File.ReadAllText(fullpath);
MAUI has a new way to access files included with the app: MauiAsset.
Described in blog Announcing .NET MAUI Preview 4, Raw Assets:
.NET MAUI now makes it very easy to add other assets to your project and reference them directly while retaining platform-native performance. For example, if you want to display a static HTML file in a WebView you can add the file to your project and annotate it as a MauiAsset in the properties.
<MauiAsset Include="Resources\Raw\index.html" />
Tip: you can also use wildcards to enable all files in a directory:
... Include="Resources\Raw\*" ...
Then you can use it in your application by filename.
<WebView Source="index.html" />
UPDATE
However, the feature MauiAsset apparently still needs improvement:
open issue - MauiAsset is very hard to use.
There we learn that for now:
Set BuildAction in each file's properties to MauiAsset.
That is, its not recommended to use the "wildcard" approach at this time. Set that build action on each file in solution explorer / your project / the file.
Accessing on Windows requires a work-around:
#if WINDOWS
var stream = await Microsoft.Maui.Essentials.FileSystem.OpenAppPackageFileAsync("Assets/" + filePath);
#else
var stream = await Microsoft.Maui.Essentials.FileSystem.OpenAppPackageFileAsync(filePath);
#endif
NOTE: This will be simplified at some point; follow that issue to see progress.
UPDATE
The current MAUI template is missing some platform-specific flags. For now, add your own flag to identify when the code is running on Windows:
Complete example in ToolmakerSteve - repo MauiSOAnswers. See MauiAssetPage.
MauiAssetPage.xaml:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiTests.MauiAssetPage">
<ContentPage.Content>
<!-- By the time Maui is released, this is all you will need. -->
<!-- The Init code-behind won't be needed. -->
<WebView x:Name="MyWebView" Source="TestWeb.html" />
</ContentPage.Content>
</ContentPage>
MauiAssetPage.xaml.cs:
using Microsoft.Maui.Controls;
using System.Threading.Tasks;
namespace MauiTests
{
public partial class MauiAssetPage : ContentPage
{
public MauiAssetPage()
{
InitializeComponent();
Device.BeginInvokeOnMainThread(async () =>
{
await InitAsync();
});
}
private async Task InitAsync()
{
string filePath = "TestWeb.html";
#if WINDOWS
var stream = await Microsoft.Maui.Essentials.FileSystem.OpenAppPackageFileAsync("Assets/" + filePath);
#else
var stream = await Microsoft.Maui.Essentials.FileSystem.OpenAppPackageFileAsync(filePath);
#endif
if (stream != null)
{
string s = (new System.IO.StreamReader(stream)).ReadToEnd();
this.MyWebView.Source = new HtmlWebViewSource { Html = s };
}
}
}
}
TestWeb.html:
(whatever html you want)
In Solution Explorer, add TestWeb.html to your project. In its Properties, select Build Action = MauiAsset.
I tried looking for a solution to this for months. I ended up hosting the file online then creating a method to download the file during runtime
public async Task DownloadFile(string fileName)
{
if (File.Exists(FileSystem.Current.AppDataDirectory + $"/{fileName}"))
{
return;
}
else
{
try
{
NetworkAccess networkAccess = Connectivity.Current.NetworkAccess;
if (networkAccess == NetworkAccess.Internet)
{
await Task.Run(() =>
{
var uri = new Uri($"https://myhostedfile.com/{fileName}");
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCallback2);//checking if download is complete
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(MaintainProgress);//event handler to check download progress
webClient.DownloadFileAsync(uri, FileSystem.Current.AppDataDirectory + $"/{fileName}");
});
}
else
await Shell.Current.DisplayAlert("No Internet", "Failed to get some files from the internet, confirm if your internet is" +
"working", "OK");
}
catch (Exception)
{
await Shell.Current.DisplayAlert("Error", "Failed to get some files from the internet, confirm if your internet is" +
"working", "OK");
}
}
}
Then you can access your file URL using:
string filePath = FileSystem.Current.AppDataDirectory + $"/myfile.pdf;

How do I download a file on both Android X and iOS that is publicly available, using Xamarin.Forms?

Looking at this issue xamarin/Essentials#1322, how do I download a file on both Android ( versions 6-10, Api 23-29 ) and iOS ( version 13.1+ ) that is publicly available (share-able to other apps, such as Microsoft Word). I don't need to give write access to the other apps, just read-only is ok if it must be restricted.
I get the following exception:
[Bug] Android.OS.FileUriExposedException: file:///data/user/0/{AppBundleName}/cache/file.doc exposed beyond app through Intent.getData()
With the following code.
public static string GetCacheDataPath( string fileName ) => Path.Combine(Xamarin.Essentials.FileSystem.CacheDirectory, fileName);
public static FileInfo SaveFile( string filename, Uri link )
{
using var client = new WebClient();
string path = GetCacheDataPath(filename);
DebugTools.PrintMessage(path);
client.DownloadFile(link, path);
return new FileInfo(path);
}
public async Task Test(Uri link)
{
LocalFile path = await SaveFile("file.doc", link).ConfigureAwait(true);
var url = new Uri($"ms-word://{path.FullName}", UriKind.Absolute);
await Xamarin.Essentials.Launcher.OpenAsync(url).ConfigureAwait(true);
}
With this answer, I created a FileService interface and it works with local private files but I am unable to share the files. Starting with Android Q (10 / Api 29), the following is deprecated.
string path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath; // deprecated
I get the following exception:
System.UnauthorizedAccessException: Access to the path '/storage/emulated/0/Download/file.doc' is denied. ---> System.IO.IOException: Permission denied
I haven't found any way yet to get a public path for Android 10 with Xamarin.Forms. I've looked at the Android Docs for Content providers but it's in Java, and I can't get it working in C# yet.
Any help would be greatly appreciated.
I did find a Solution
Found a fix
For Android
public Task<System.IO.FileInfo> DownloadFile( Uri link, string fileName )
{
if ( link is null )
throw new ArgumentNullException(nameof(link));
using System.Net.WebClient client = new System.Net.WebClient();
// MainActivity is the class that loads the application.
// MainActivity.Instance is a property that you set "Instance = this;" inside of OnCreate.
Java.IO.File root = MainActivity.Instance.GetExternalFilesDir(MediaStore.Downloads.ContentType);
string path = Path.Combine(root.AbsolutePath, fileName);
client.DownloadFile(link, path);
return Task.FromResult(new System.IO.FileInfo(path));
}
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
...
Instance = this;
...
}
...
}
For iOS
public Task<System.IO.FileInfo> DownloadFile( Uri link, string fileName )
{
if ( link is null )
throw new ArgumentNullException(nameof(link));
using System.Net.WebClient client = new System.Net.WebClient();
string path = Path.Combine(Xamarin.Essentials.FileSystem.CacheDirectory, fileName)
client.DownloadFile(link, path);
return Task.FromResult(new System.IO.FileInfo(path));
}
public async Task Share()
{
// back in shared project, choose a file name and pass the link.
System.IO.FileInfo info = await DependencyService.Get<IDownload>().DownloadFile(new Uri("<enter site>", "file.doc").ConfigureAwait(true);
ShareFile shareFile = new ShareFile(info.FullName, "doc"); // enter the file type / extension.
var request = new ShareFileRequest("Choose the App to open the file", shareFile);
await Xamarin.Essentials.Share.RequestAsync(request).ConfigureAwait(true);
}
Note that for iOS, due to Apple's infinite wisdom... I cannot share the file directly with another app as I can on Android. Sandboxing is good for security but in this case, how they implemented it, it limits options. Both Applications must be pre-registered / pre-allocated in an "App Group" to share files directly. See this Article and the Apple Docs for more information.

Writing logs to file using Xamarin.Forms and Serilog

Hello I am having trouble writing logs to file on Android device using Xamarin.Forms (.NET Core shared project) and Serilog.
So far I have installed Serilog in Shared project. Installed Serilog, Serilog.Sinks.File, and Serilog.Sinks.Xamarin to my Android project and initialized logger in MainActivity:
Log.Logger = new LoggerConfiguration()
.WriteTo.File(Path.Combine(Environment.ExternalStorageDirectory.AbsolutePath,"XamarinLib-{Date}.txt"),
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}",
fileSizeLimitBytes: 100000000,
rollingInterval: RollingInterval.Day,
rollOnFileSizeLimit: true,
shared: false,
retainedFileCountLimit: 31,
encoding: Encoding.UTF8)
.WriteTo.AndroidLog()
.CreateLogger();
Afterwards I call the logger from shared project like:
Log.Information("Test writing to log file");
I can see the log command being executed in Visual Studio debug output, but the file is simply not created.
I've tried multiple locations on both emulator and actual device (no root access).
I've also tried to use RollingFile sink in similar manner with no success.
Any ideas?
First, you have to allow permissions in your AndroidManifest.xml file.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Next, The user either must, approve that on runtime in which you have to code this in your code behind. NOTE Remember to add Plugin.Permissions on your NUGET package:
InitializeComponent();
Task.Run(async () =>
{
try
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
if (status != PermissionStatus.Granted)
{
var accepted = await DisplayAlert("Storage Permission Required",
"Please enable your storage permission, it will be used to store logs and crashes",
"ACCEPT",
"CANCEL");
if(accepted)
{
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Storage);
status = results[Permission.Storage];
}
}
}
catch (Exception ex)
{
await DisplayAlert("Exception ex", "Exception ex", "OK");
}
});
OR
let them change the permissions in the settings -> app -> permissions.
Finally,
change the filename that will link to the storage/emulated/0/[your added directory].
After the closing the app, you can see it in the Android File Manager.
as pointed out by Ruben Bartelink the problem is that Android can't simply write to external storage (ie /storage/emulated/0... etc..).
I was able to log to a file on a Xamarin.Forms project in both Android and iOS.
_Tmp = System.IO.Path.GetTempPath();
_Path = System.IO.Path.Combine(_Tmp, "Serilog.txt");
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File(_Path, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7)
.CreateLogger();
Log.Information("Started new serilogger {SERILOG} on file {FILE}", this, _Path);
Log.CloseAndFlush();
//test
foreach (string log in System.IO.Directory.GetFiles(_Tmp, "*.txt"))
{
string test = System.IO.File.ReadAllText(log);
System.Diagnostics.Debug.WriteLine($"Test[{log}] -> {test}");
}
which printed on the debug console:
[0:] Test[/data/user/0/com.******/cache/Serilog20190819.txt] -> 2019-08-19 16:00:36.997 +02:00 [INF] Started new serilogger ******.Functions.Serilogger on file /data/user/0/com.******/cache/Serilog.txt

Could not initialize Tesseract API with language=eng

I am working on an Android app that requires OCR. I have decided to use Tesseract as API but I keep on getting this error:
E/Tesseract(native): Could not initialize Tesseract API with language=eng!
I have already copied file "eng.traineddata" to the location.
I am using Android Studio 2.1.2 (SDK 23)
Testing on device with API 22 Android Lollipop 5.1.1 (Read about Permission issue on Marshmallow)
Here is the code I am using:
public void reads(View view) {
TextView textView = (TextView) findViewById(R.id.textView);
int rotation = 0;
try {
ExifInterface exifInterface = new ExifInterface(mCurrentPhotoPath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL);
switch (orientation){
case ExifInterface.ORIENTATION_ROTATE_90: rotation = 90; break;
case ExifInterface.ORIENTATION_ROTATE_180: rotation = 180; break;
case ExifInterface.ORIENTATION_ROTATE_270: rotation = 270; break;
}
} catch(Exception e) {
}
int w = imageBitmap.getWidth();
int h = imageBitmap.getHeight();
if (rotation != 0) {
Matrix matrix = new Matrix();
matrix.preRotate(rotation);
imageBitmap = Bitmap.createBitmap(imageBitmap,0,0,w,h,matrix,false);
} else {
imageBitmap = Bitmap.createBitmap(imageBitmap,0,0,w,h);
}
imageBitmap = imageBitmap.copy(Bitmap.Config.ARGB_8888,true);
TessBaseAPI ReadIt = new TessBaseAPI();
ReadIt.init("/storage/emulated/0/","eng");
ReadIt.setImage(imageBitmap);
String Text = ReadIt.getUTF8Text();
if (Text!=null) textView.setText(Text);
}
I have used this line in my build.gradle dependency:
compile 'com.rmtheis:tess-two:6.0.2'
also, I have copied the"eng.traineddata in the folder named tessdata directly by downloading in the particular stated directory.
Tesseract-two isn't using the newest version of the OCR engine, it uses 3.05, so we are forced to use data from here. It seems the new data uses a different model, neural networks. The previous models before 4.0 worked differently.
I have tried using the data from here
and here. These data sets are only compatible with the newest version of tesseract, 4.0 (source), so it won't work if you are using an older version of tesseract.
Are you using tess-two?. In your code:
TessBaseAPI ReadIt = new TessBaseAPI();
ReadIt.init("/storage/emulated/0/","eng");
"/storage/emulated/0/" path should be pointing to your data files. You must have a subdirectory
named "tessdata". See
https://github.com/rmtheis/tess-two/blob/d7a45fd2e08b7ec315cd1e29d1a7e0c72fb24a66/tess-two/src/com/googlecode/tesseract/android/TessBaseAPI.java#L176
Read more at:
Could not initialize Tesseract API with language=eng!
Release permissions of manifest in Activity:
In manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
In onCreate:
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
1);
}
}
If you dont use Marshmallow and still have problem try clean and rebuild project.
I had this same issue and the problem was that Marshmallow specifically requires a new way for your app to get read/write permission to storage. This blog post solved my problem.
In my Main Activity I have the following:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
...
getStorageAccessPermissions(); // Request storage read/write permissions from the user
}
#TargetApi(23)
private void getStorageAccessPermissions() {
int hasWriteStoragePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (hasWriteStoragePermission != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_EXTERNAL_PERMISSIONS);
}
}
Where REQUEST_CODE_WRITE_EXTERNAL_PERMISSIONS is an integer constant declared globally.
In a class that I have extending TessBaseAPI I added the following just for logging purposes to make sure that I actually can access the storage.
/* Checks if external storage is available to at least write to and returns the path name */
private static String isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
String retval = "External storage is not writable";
if (Environment.MEDIA_MOUNTED.equals(state)) {
retval = Environment.getExternalStorageDirectory().toString();
}
return retval;
}
/* Checks if external storage is available to at least read from and returns the path name */
private static String isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
String retval = "External storage is not readable";
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
retval = Environment.getExternalStorageDirectory().toString();
}
return retval;
}
use absolute path to tessdata directory from external storage (not assets)
for example if your models are in
/storage/emulated/0/Android/data/com.xxx.yyy/files/tessmodels/tessdata/
use this path
/storage/emulated/0/Android/data/com.xxx.yyy/files/tessmodels/
make sure you have write/read external storage permissions
use this model, tested with tess-two:9.0.0. I got it from tess-two sample app
Newer versions of tess-two check to make sure that the training data files can be found on the device. If those training data files are not found, a more informative message than the error message you're seeing will be shown.
So when you see this error message on newer versions of tess-two, it means that the training data files were found in the expected location, but they are the wrong version or are otherwise unreadable. Check to make sure you're using the right version of the training data files.

Send Logcat output of an App to an EmailAdress

We are now testing our application with a few friends. Sometimes there are some errors which don't throw an exception. So I don't really know whats the problem was. So I thought it would be a good idea to implement a menu item which allows to send the logcat output to a e-mail address, so that we can examine the log.
Unfortunately I didn't find a hint in the Internet how to extract the logcat from a phone. How to send an email shouldn't be the problem.
Look at android-log-collector, as it does what you are trying to do.
It is not possible to collect arbitrary LogCat data as of Android 4.1. There was never a documented and supported way of doing that, and the undocumented/unsupported way was locked down in Jelly Bean. For your own crashes, you are better served using a crash logging library, like ACRA.
I would also look into Flurry (flurry.com) which not only gives you general analytics but allows you to log arbitrary info and also logs uncaught exceptions for you. I set it up in literally 5 minutes, but one thing to keep in mind is that it's not real-time like an email alert. You'll have to wait a few hours for what you log in your app to show up on their dashboard. It could also be overkill if you have a really lightweight app, but I've noticed no performance loss in my app as a result of using the service.
I found the LogCollector very usefull indeed (the tip from CommonsWare):
And don't forget to set in your own application:
<uses-permission android:name="android.permission.READ_LOGS" />
I'd definitely recommend to look also at this project here
This solution doesn't send an email, but sends it to a server through UDP.
https://github.com/Chemik/logcatudp
The source code is available. It can be easily embedded in our own app. I haven't tried to do so.
In your manifest file give the following permissions:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
In your first/launcher activity, right after the
super.onCreate(savedInstanceState);
Write below lines: This will write your App's logcat to your device's external storage
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_PERMISSION_CODE);
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, READ_PERMISSION_CODE);
}
if ( isExternalStorageWritable() ) {
File appDirectory = new File( Environment.getExternalStorageDirectory() + "/MyAppLog" );
File logDirectory = new File( appDirectory + "/log" );
File logFile = new File( logDirectory, "logcat" + ".txt" );
// create app folder
if ( !appDirectory.exists() ) {
appDirectory.mkdir();
}
// create log folder
if ( !logDirectory.exists() ) {
logDirectory.mkdir();
}
// clear the previous logcat and then write the new one to the file
if ( logFile.exists()){
logFile.delete();
}
try {
Process process = Runtime.getRuntime().exec("logcat -c");
process = Runtime.getRuntime().exec("logcat -f " + logFile);
} catch ( IOException e ) {
e.printStackTrace();
}
} else if ( isExternalStorageReadable() ) {
// only readable
} else {
// not accessible
}
For sending the logcat to desired email address: use below method
public void sendLogcatMail(){
if ( isExternalStorageWritable() ) {
File appDirectory = new File(Environment.getExternalStorageDirectory() + "/MyAppLog");
File logDirectory = new File(appDirectory + "/log");
File logFile = new File(logDirectory, "logcat" + ".txt");
if (logFile.exists()) {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("vnd.android.cursor.dir/email");
String to[] = {"yourEmailAddress#gmail.com"};
emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(String.valueOf(logFile.toURI())));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Log files");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Send some message along");
startActivity(Intent.createChooser(emailIntent, "Send email..."));
}
}
}
Method for checking whether the permissions for Writing to External storage is given or not:
/* Checks if external storage is available for read and write */
public static boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if ( Environment.MEDIA_MOUNTED.equals( state ) ) {
return true;
}
return false;
}
Thanks to you 2 but by browsing the android-log-collector forum I found a solution that is even easier to handle:
There you can store a php file somewhere on your server (or if you dont want to use your own server, they also have a script on their server). In this php file you can define what shall be done when the post message reaches the server. I just definded a very simple code which forwards the data to my mail adress.
This only works if an uncaught exception was thrown. But one could extend the default uncaught exception handler, so that it's also possible to not only get the stacktrace but also the logcat.

Categories

Resources