Xamarin.Android : System.UnauthorizedAccessException: Access to the path is denied - xamarin.android

I am targeting Android API 30. My app was storing log file and taking database backup in location "/storage/emulated/0/SpecialDir/". Now I am facing access denied issue while my app was workinng fine previously.
I got an overview about scoped storage and came to know that we have some managed locaitons where we can store our data accordingly. i.e Audio, Video, Images, and Download
My question is What is the solution for existing apps that was previously saving files on "/storage/emulated/0/SpecialDir/".
Can anyone please guide me what should i do.
string dir = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.ToString(), "LogFolder");
if (Directory.Exists(dir))
{
return Path.Combine(dir, "MyLogFile.txt");
}
try
{
string newDirectory = Directory.CreateDirectory(dir).FullName;
path = Path.Combine(newDirectory, "MyLogFile.txt");
System.IO.File.WriteAllText(path, "This is some testing log.");
}
catch (Exception ex)
{
string msg = ex.Message;
}
The above code is used to make 'LogFolder' if not exist and 'MyLogFile' as well. What changes do i needed to make it compatiable to Android 10. Thankyou

In Android 10, Google has introduced a new feature for external Storage. Its name is Scoped Storage. Google officially translates it as partitioned Storage, or Scoped Storage.The intent is to limit what programs can do with public directories in external storage. Partitioned storage has no effect on either the internal storage private directory or the external storage private directory.In short, in Android 10, there is no change to private directory reads and writes, and you can still use the File set without any permissions. For reading and writing to public directories, you must use the API provided by MediaStore or the SAF (storage access framework), which means you can no longer use the File set to manipulate public directories at will.
If you set targetSdkVersion above 29,you could try to add below codes into your AndroidManifest.Then you could access the File as before.
<manifest ... >
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
Update (you could try this for public external storage ):
var path = Android.OS.Environment.GetExternalStoragePublicDirectory("LogFolder").AbsolutePath;
Java.IO.File file = new Java.IO.File(path);
if (!file.Exists())
{
file.Mkdirs();
}
try
{
FileWriter fw = new FileWriter(path + Java.IO.File.Separator + "MyLogFile.txt");
fw.Write("This is some testing log.");
fw.Close();
}
catch (Exception ex)
{
string msg = ex.Message;
}
Update for Android 11:
add MANAGE_EXTERNAL_STORAGE permission in your AndroidManifest.
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
in your activity:
if (Environment.IsExternalStorageManager)
{
var path = Android.OS.Environment.GetExternalStoragePublicDirectory("LogFolder").AbsolutePath;
Java.IO.File file = new Java.IO.File(path);
if (!file.Exists())
{
file.Mkdirs();
}
try
{
FileWriter fw = new FileWriter(path + Java.IO.File.Separator + "MyLogFile.txt");
fw.Write("This is some testing log.");
fw.Close();
}
catch (Exception ex)
{
string msg = ex.Message;
}
}
else
{
StartActivityForResult(new Intent(Settings.ActionManageAllFilesAccessPermission), 0);
}

Related

Messages not rendered when a pst is created from email messages located in another machine on a same network

I am creating a pst from message files which are located in another machine on a same network. But when I loaded the pst, messages are not rendered. I have added a screenshot. And code is below:
Issue do not occur when message files are imported from my local machine.
private static void GeneratePST(string [] messageFiles, string outputPstPath)
{
RDOSession pstSession = null;
RDOPstStore store = null;
RDOFolder folder = null;
RDOMail rdo_Mail = null;
RDOItems items = null;
try
{
pstSession = new RDOSession();
store = pstSession.LogonPstStore(outputPstPath, 1, Path.GetFileNameWithoutExtension(outputPstPath));
folder = store.IPMRootFolder;
folder = folder.Folders.Add("Loose Messages");
foreach (string messages in messageFiles)
{
items = folder.Items;
rdo_Mail = items.Add("IPM.NOTE");
rdo_Mail.Import(messages, rdoSaveAsType.olMSG);
rdo_Mail.Save();
}
}
catch (Exception ex)
{
//log exception
}
finally
{
Marshal.ReleaseComObject(rdo_Mail);
Marshal.ReleaseComObject(folder);
Marshal.ReleaseComObject(store);
Marshal.ReleaseComObject(items);
pstSession.Logoff();
Marshal.ReleaseComObject(pstSession);
GC.Collect();
}
}
I have also impersonated the network machine before importing message file. But still the issue persist.
The problem only exists for files in another machine. Messages are rendered for msg file located in my machine. Also, I noticed issue is only with message files. Eml file are rendered. So, it might not be the issue of impersonation.
Any help please.
Microsoft does not support accessing PST files on network drives. They must be on a local machine.
Also, there is no reason to continuously retrieve the RDOItems object - you never release on the old value, so those objects stay alive until your app exits. Ditto for the rdo_Mail object:
folder = folder.Folders.Add("Loose Messages");
items = folder.Items;
foreach (string messages in messageFiles)
{
if (rdo_Mail != null) Marshal.ReleaseComObject(rdo_Mail);
rdo_Mail = items.Add("IPM.NOTE");
rdo_Mail.Import(messages, rdoSaveAsType.olMSG);
rdo_Mail.Save();
}

Xamarin.iOS: Saving files to windows shared folder

I have an iOS app written using Xamarin. Is there a way to save some file (in my case Image) to a shared folder on Windows PC? iOS device and PC are in the same WiFi network, so I can get access to PC machine by IP address. But how can I save a file to that shared folder?
If that is possible I would be grateful for some code example.
Are you try SharpCifs.Std?
NuGet Package is here.
drives SMB on Xamarin.iOS, like this.
var file = new SmbFile("smb://UserName:Password#ServerName/ShareName/Folder/NewFileName.txt"));
file.CreateNewFile();
var writeStream = file.GetOutputStream();
writeStream.Write(Encoding.UTF8.GetBytes("Hello!"));
In my Xamarin application (on iPad Pro 12.9") I kind of worked around this problem by activating FTP on my Windows10 machine (see Google how to do this) and then uploaded the image to the Windows folder via FTP:
private void UploadImage(UIImage image, string fileName)
{
try
{
string ftpPath = "ftp://192.168.47.79/"; // IP of my Windows10 pc
string ftpTargetFilePath = $"{ftpPath}{fileName}";
var credentials = new NetworkCredential("ftpuser", "ftp");
FtpWebRequest request = (FtpWebRequest) WebRequest.Create(ftpTargetFilePath);
request.Credentials = credentials;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UsePassive = false; // in my case I needed passive mode to be deactivated
using (Stream imageStream = image.AsPNG().AsStream())
{
using (Stream ftpStream = request.GetRequestStream())
{
imageStream.CopyTo(ftpStream);
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Uploading Image: Failed! ({ex.Message})");
}
}

Struts file uploaded to certain directory, not able to retrieve back?

I am running Eclipse Java EE and tomcat for running my webapp. I used the following code to store an image file to the upload/images/profilepics directory:
public String uploadPhoto() {
try {
//get path to upload photo
String filePath = servletRequest.getSession().
getServletContext().getRealPath("/uploads/profilepics");
System.out.println("Server path:" + filePath);
//creating unique picture name
Map sess = (Map) ActionContext.getContext().get("session");
Integer uid = (Integer) sess.get("uid");
String profilePictureName = uid + "-" +
MyUtilityFunctions.createVerificationUrl() + this.userImageFileName;
//update user record
//tobe done
String imgUrl = filePath + profilePictureName;
ViewProfileModel pofilePictureUpdate = new ViewProfileModel();
pofilePictureUpdate.updateUserPhotoUrl(imgUrl, uid);
//create new File with new path and name
File fileToCreate = new File(filePath, profilePictureName);
//copy file to given location and with given name
FileUtils.copyFile(this.userImage, fileToCreate);
} catch (Exception e) {
e.printStackTrace();
addActionError(e.getMessage());
return INPUT;
}
return SUCCESS;
}
after printing filePath I got the following result:
Server Path: /home/bril/webspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/picvik/uploads/profilepics
Now the problem is, I am not able to get the image or if I give the same url to <img src=""> nothing is getting displayed.
Please correct where I am doing wrong.
There are suggestions:
there are lots of reason, that you shouldn't save user images in this way, just like #DaveNewton mentioned in another question. There
are some post to help you make your decision:
Post1
Post2
My personal opinion is to save them into DB, because you don't want
to let your user lost their images.
If you need access session, you can check out SessionAware. This should be a better way to access session.
You are using tomcat as application container, you can configure the server to use its local installation, which makes you easier to track the problem in this case. check out this picture below
Back to your question, There are different ways to do this:
if you cannot find the image user just uploaded, you can check it
manual, see 3.
Otherwise, you could try <img src="/uploads/profilepics/<s:property
value='profilePictureName'/>"
Or you can get this picture using stream, here is the snippet:
JSP:
<img src="
<s:url var="profilePic" action="customer-image-action">
<s:param name="uid" value="%{uid}"/>
</s:url>
" alt="kunden logo" />
Action:
public String execute() throws Exception {
// filename = somehow(uid);
HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);
imgPath = request.getSession().getServletContext().getRealPath("/uploads/profilepics/")+filename;
log.debug("context-path: " + imgPath);
try {
inputStream = FileUtils.openInputStream(new File(imgPath));
} catch (IOException e) {
log.error(e.getCause(), e);
}
return SUCCESS;
}

Cannot Write On Micro SDCard On BlackBerry

I am trying to save some files on micro SDCard. To check the availability of SDCard, I am using the following method;
private boolean isSdCardReady() {
Enumeration e = FileSystemRegistry.listRoots();
while (e.hasMoreElements()) {
if (e.nextElement().toString().equalsIgnoreCase("sdcard/")) {
return true;
}
}
return false;
}
Even if this method returns true, when I try to save files, it gives exception net.rim.device.api.io.file.FileIOException: File system is not ready.
What does this means? If SDCard is not available, then why its listed in FileSystemRegistry.listRoots()?
How can I make sure that SDCard is available for writing?
My development environment:
BlackBerry JDE Eclipse Plugin 1.5.0
BlackBerry OS 4.5
BlackBerry Bold with a 3G card
Usually I had this error when I tried to access SD card on device restart. You have to postpone all operations in app until startup finished:
while (ApplicationManager.getApplicationManager().inStartup()) {
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
I remember one more possible cause mentioned here. You have to close all streams after using.
Solved the problem. I was looking for "sdcard" while rootsEnum.nextElement().toString(); returns "SDCard". Yeah, its case sensitive. Now, instead of using hard-coded "SDCard", I've changed the above method to the following;
private static String getSdCardRootDir() {
Enumeration rootsEnum = FileSystemRegistry.listRoots();
while (rootsEnum.hasMoreElements()) {
String rootDir = rootsEnum.nextElement().toString();
if (rootDir.equalsIgnoreCase("sdcard/")) {
return "file:///" + rootDir;
}
}
return null;
}
Using this, I got the root directory in its system defined case.

how to create database in blackberry mobile

List item
i developed an application , in which uses sq lite database . this is running properly on simulater . but when we application deploy on Blackberry curve 8520 mobile then . tell us database does not exist. anyone know answer please quick response ...
My Code is ->
public static void insertData( String pass , String cpass)
{
boolean fl=false;
String root = null;
MainScreen ms = new MainScreen();
Enumeration e = FileSystemRegistry.listRoots();
while (e.hasMoreElements())
{
root = (String)e.nextElement();
if(root.equalsIgnoreCase("store/"))
{
fl=true;
}
}
if(!fl)
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("This application requires an SD card to be present." +
"Exiting application...");
System.exit(0);
}
});
}
else
{
String dbLocation = "C:/om12345/sql/res/store/";
// Create URI
// Statement st=null;
try
{
URI myURI = URI.create("file:///store/home/user/databases/database.sqlite");
//URI myURI1=URI.
d = DatabaseFactory.create(myURI);
Statement st = d.createStatement( "insert into Admin (pass, Cpass) values('"+ pass+"','"+cpass+"')");
st.prepare();
st.execute();
st.close();
d.close();
//ms.add(new RichTextField ("tata" + "tata1"));
// UiApplication.getApplication.invokeLater(pushScreeen(ms));
}
catch ( Exception e1 )
{
System.out.println( e1.getMessage() );
e1.printStackTrace();
}
}
You likely can't store a sqlite database on /store for the 8520. See my answer to BlackBerry SQLite database creation: "filesystem not ready" for more information on that.
You will first need to change the line that says " String dbLocation = "C:/om12345/sql/res/store/";" since that refers to a location on your development machine but will not work on a mobile device. You need to point to the 'res' folder in your application itself.
You can not create database into store directory if you are having less than 1gb internal storage & you have saved your data base in C directory , which can be accessible from your system, but not on device. So change its location copied into it res folder.
& check if you are having SD card then save your database using /SDCard.
If SDCard is not available than you will able to access database , if you are having more than 1GB internal storage
have a look on this link
http://docs.blackberry.com/en/developers/deliverables/17952/SQLite_database_files_1219778_11.jsp

Resources