天道酬勤,学无止境

Delphi XE5 Android - Storage path problems

I started doing an app for android in Delphi XE5, and encountered some troubles.

I really don't understand about getting paths. After I set the permissions to Write and Read External storage, I tried to get paths so I can see where I'm saving files I create, and this is what I get:

for System.IOUtils.TPath. ->

GetDocumentsPath;       -  /data/data/com.myapp.app1/files
GetDownloadsPath;       -  /storage/emulated/0/Android/data/com.myapp.app1/files/Download
GetHomePath;            -  /data/data/com.myapp.app1/files
GetSharedDocumentsPath; -  /storage/emulated/0/Android/data/com.myapp.app1/files
GetLibraryPath;         -  /data/data/com.myapp.app1/files
GetPublicPath;          -  /storage/emulated/0/Android/data/com.myapp.app1/files
GetPicturesPath;        -  /storage/emulated/0/Android/data/com.myapp.app1/files/Pictures

As far as I understood from other topics, the GetDocumentsPath should be default sdcard path, Downloads should be sdcard/Downloads, but instead it's using /Android/data/application's folder/files/ here creats folders which already exists on the sdcard itself.

/emulated/0/ is actually the same as /sdcard/ on my phone, if that's confusing for anyone (just in case....).

It has several shortcuts, as far as I understand, storage/emulated/0/, storage/sdcard0/, also from root's folder is directly access to sdcard/ (but I guess the apps without root access has only default access to storage/ folder, hence the storage/sdcard0 and emulated/0 folders exists; don't know why are duplicated shortcuts to the same folder, though....)

[[ There's also storage/emulated/legacy/, which also seems to point to the same folder, but I never touch it, since I used to have some troubles with file duplicates and strange Music library behaviour, right before I rooted and formatted it. Never figured what really happened, but don't even care. Fact is, that the emulated folder seems to be evil and unexplained ;) ]]

Also, are these path troubles related to the fact, that the phone has no mount option, but only MTP, or that it's android 4.3, or....?

Thanks.

// Update: Splitted questions about this and screen resolutions as Sir Rufo suggested.

UPDATE: Looks like hardcoding '/sdcard/filename.extension' as path string does the job, however I'm not sure how wise it is to hardcore the location in the app... ://

评论

Try not to hard code the path. The paths to external storage may vary for different Android platforms and you'll miss the advantage of cross-platform programming. When I started programming for Android I wrote a small App 'Where' targeted at listing all 'special' directories for all platforms. That was very useful as I didn't know these directories for even Windows, let alone Android. In your example you miss the SharedDirectories. This will return the path to /storage/emulated/0/Music/ for GetSharedMusicPath for example, and so on for Movies, Download, etc. I thought it was different for my Galaxy Tab but I'm not sure. Just remove the last name and you have the path to external storage.

Take care that you have READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE set if you want to read and write to your external storage (somewhere in Project | Options | Android). I don't know whether Android allows you to write in the external storage root, you must try that yourself.

uses System.IOUtils;

procedure THeaderFooterForm.Loaded;
begin
   inherited Loaded;

   TPath.SetApplicationPath ('WhereAppTest');

   add_path (TPath.GetTempPath, 'GetTempPath');
   add_path (TPath.GetHomePath, 'GetHomePath');
   add_path (TPath.GetDocumentsPath, 'GetDocumentsPath');
   add_path (TPath.GetApplicationPath ('WhereAppTest'), 'GetApplicationPath');
   add_path (TPath.GetSharedDocumentsPath, 'GetSharedDocumentsPath');
   add_path (TPath.GetLibraryPath, 'GetLibraryPath');
   add_path (TPath.GetCachePath, 'GetCachePath');
   add_path (TPath.GetPublicPath, 'GetPublicPath');
   add_path (TPath.GetPicturesPath, 'GetPicturesPath');
   add_path (TPath.GetSharedPicturesPath, 'GetSharedPicturesPath');
   add_path (TPath.GetCameraPath, 'GetCameraPath');
   add_path (TPath.GetSharedCameraPath, 'GetSharedCameraPath');
   add_path (TPath.GetMusicPath, 'GetMusicPath');
   add_path (TPath.GetSharedMusicPath, 'GetSharedMusicPath');
   add_path (TPath.GetMoviesPath, 'GetMoviesPath');
   add_path (TPath.GetSharedMoviesPath, 'GetSharedMoviesPath');
   add_path (TPath.GetAlarmsPath, 'GetAlarmsPath');
   add_path (TPath.GetSharedAlarmsPath, 'GetSharedAlarmsPath');
   add_path (TPath.GetDownloadsPath, 'GetDownloadsPath');
   add_path (TPath.GetSharedDownloadsPath, 'GetSharedDownloadsPath');
   add_path (TPath.GetRingtonesPath.Empty, 'GetRingtonesPath');
   add_path (TPath.GetSharedRingtonesPath, 'GetSharedRingtonesPath');
   FMediaPlayer := TMediaPlayer.Create(Self);
end; // Loaded //

procedure THeaderFooterForm.add_path (path, header: string);
var
   item: TListViewItem;
   bitmap: TBitmap;
begin
   item := List_Paths.Items.Add;
   item.ButtonText := 'button';
   item.Detail := path;
   item.Text := header;
end; // add_path //

Here's the function that will get you the default SDCard path from GetShared paths; The first is simple and will get you just the SDCard path from fixed path of the SharedMusic;

function GetSDCardPath: string;
var MusicPathLength: integer;
    MusicPath, SDCardPath: string;
begin
  MusicPath:=System.IOUtils.TPath.GetSharedMusicPath;
  MusicPathLength:=Length(MusicPath);
  SDCardPath:=Copy(MusicPath, 0, MusicPathLength-5);
  Result:=SDCardPath;
end;

I could add the function to extract sdcard path from any of provided paths results, but I think the example above is the most simple you could use, and works flawlessly for me. Thanks to @Arnold for help too. :)

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 使用Delphi XE5在Android和iOS中获取SD卡和可执行文件路径(Get SD card and executable path in Android and iOS with Delphi XE5 [closed])
    问题 关闭。 此问题不符合堆栈溢出准则。 它当前不接受答案。 想要改善这个问题吗? 更新问题,使它成为Stack Overflow的主题。 7年前关闭。 改善这个问题 我如何获取SD卡路径以及如何使用Delphi XE5在Android和iOS中获取可执行文件路径? 回答1 使用System.IoUtils.TPath。 通过使用TPath.GetDocumentsPath获取SD卡路径,并且应使用TPath.GetHomePath找到应用程序的基本目录。 uses IOUtils; var AppPath, CardPath: string; AppPath := TPath.GetHomePath; CardPath :- TPath.GetDocumentsPath; TPath中还有其他一些与系统路径相关的功能,包括这些功能(还有许多其他功能-由于文档尚不清楚,因此您必须查看哪些功能适用于Android和iOS)。 GetTempPath GetPublicPath GetCameraPath GetMusicPath GetDownloadsPath
  • Get SD card and executable path in Android and iOS with Delphi XE5 [closed]
    Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers. Want to improve this question? Update the question so it's on-topic for Stack Overflow. Closed 7 years ago. Improve this question How do I get the SD card path and how do I get the executable path in Android and iOS using Delphi XE5?
  • Delphi XE5从右到左的语言没有像在Android中那样出现(Delphi XE5 right to left languages don't appear as they should in android)
    问题 如标题所述,来自RTL语言(如波斯语或阿拉伯语)的文本在android中显示效果不佳,例如单词“سلام”显示为“مالس”。 即使在文本输入中也会发生此问题(我认为它们是本机的,本机的android文本框支持该功能)是否有解决此问题的方法? 回答1 根据利比里亚人和解与民主党的建议。 下载并使用DPF Delphi Android本机组件和/或DPF Delphi iOS本机组件。 这将解决XE7及更早版本中的问题。 根据有关Delphi XE8 beta的文档,此问题也已修复。 作为最后的选择(如果您愿意的话),有人努力修补XE5源代码以启用BiDi支持。 请参阅:https://docs.google.com/file/d/0BwumWe43CaijVDRQZzNQbXNSLWc/edit?usp=sharing 回答2 缺少双向和字形整形支持是FireMonkey平台在所有目标(包括Windows和Mac OSX)上的已知限制。 我们将不得不等待Android的“本机控件”作为FireMonkey的第三方组件,因为它确实存在于iOS中-例如,请参见http://www.tmssoftware.com/site/tmsicl.asp。 我找到了这篇很棒的博客文章,其中包含有关Lazarus / FreePascal的Android本机控件的源代码,这很有趣。
  • Delphi XE5中的Android后台服务(Android background service in Delphi XE5)
    问题 我需要使用delphi XE5(firemonkey)为Android编写一些服务。 该服务需要在backgroung中运行并定期读取sms收件箱,并将其写入sqllite DB(sms备份)。 我知道如何读取短信以及如何将其写入数据库,但是我不知道如何使应用程序在后台作为服务工作。 有任何想法吗? PS:谢谢您的回答。 PPS:对不起,我的英语不好。 回答1 您不能仅靠XE5来做到这一点,但是可以在Java的一点帮助下做到这一点。 布赖恩·朗(Brian Long)就此主题发表了两篇文章: http://blog.blong.com/2013/11/delphi-and-android-services.html http://blog.blong.com/2013/11/delphi-and-android-services-part-2.html 回答2 Android服务与Windows服务不同。 如果您确实使用Android服务,则该服务仍将在应用程序的主线程中运行。 当设备进入睡眠模式时,它们停止。 同样,系统可以在内存不足和其他情况下终止服务。 从文档中: 通常,已启动的服务执行单个操作,并且不将结果返回给调用方。 例如,它可能通过网络下载或上传文件。 操作完成后,服务应自行停止。 和 “如果该服务已启动并且正在长期运行,那么随着时间的流逝
  • XE5 Android TBitmap.LoadFromStream在线程内失败(XE5 Android TBitmap.LoadFromStream fail inside a thread)
    问题 我正在使用Delphi XE5为Android创建一个简单的游戏。 我有一些资源,PNG和Jpeg,我想在程序加载所有资源时显示一个加载屏幕。 但是我发现将TBitmap.LoadFromFile或TBitmap.LoadFromStream代码放入一个android线程中,导致该应用立即退出并返回到Launcher,在调试模式下,Delphi甚至都没有捕获到异常。 (该代码在Windows上完美运行,在Android上没有线程) 我必须打开logcat才能看到发生了什么,我看到了类似“创建图形上下文时出错”的信息。 我的问题是有没有一种方法可以使用Delphi XE5为Android制作加载屏幕? 这样,当图像加载到内存中时,将显示进度屏幕。 我创建测试项目只是为了隔离问题,这是结果。 LoadFromFile是线程1。日志表明线程实际上已运行,但是此后引发了异常??? Logcat屏幕截图: 源代码:http://www.pockhero.com/wp-content/uploads/2013/10/threadtest1.7z 回答1 这显然是应该在下次更新中修复的错误。 要将修补程序应用于您的代码,请声明以下过程: uses Androidapi.NativeActivity, Posix.Pthread; procedure MyEndThreadProc
  • Delphi XE5 right to left languages don't appear as they should in android
    as the title says , a text from a RTL language like persian or arabic doesnt show well in android for example the word "سلام" shows as "م ا ل س". this problem happens even in text inputs (which i thought they were native and native android textboxes support that) is there a way to fix this?
  • XE5 Android TBitmap.LoadFromStream fail inside a thread
    I am creating a simple game for Android using Delphi XE5. I have a few resources, PNGs and Jpegs, I wanted to show a loading screen while my program loads up all the resources. But I found putting TBitmap.LoadFromFile, or TBitmap.LoadFromStream code inside a android thread, caused the App to quit immediately and return to Launcher, in debug mode Delphi don't even catch an exception. (The code works perfectly on Windows, and without thread on Android) I had to open logcat to see what went on, I saw something like "Error creating drawing context". My question is there a way to make a loading
  • 如何在Android上保存文件? (火猴)(How to save a file on Android? (Firemonkey))
    问题 如何使用Delphi(XE5,Firemonkey)在Android设备上本地保存文件? 像这样简单 Memo.Lines.SaveToFile('test.txt') 似乎不起作用。 它导致以下错误消息: “无法创建文件“ /test.txt”。不是目录。” 回答1 根据创建Android应用程序文档,获取文档路径,如下所示: System.IOUtils.TPath.GetDocumentsPath + System.SysUtils.PathDelim + 'myfile'; 回答2 代替使用System.SysUtils.PathDelim ,您可以使用 System.IOUtils.TPath.Combine(System.IOUtils.tpath.getdocumentspath,'test.txt'); Combine在Windows \和Linux /之间进行选择 必须在此行中使用System.IOUtils ,而不是在uses子句中进行设置,因为可能会有更多的Tpath缩写。 回答3 GetHomePath,返回带有路径的字符串。 ->“数据/数据//文件” 您可以使用: Memo.Lines.SaveToFile(format('%s/test.txt', [GetHomePath])); 或这种形式 Memo.Lines.SaveToFile
  • 如何检查Android和iOS(Delphi XE5)上的网络是否可用(How to check if network is available on Android and iOS ( Delphi XE5 ))
    问题 如何检查Android和iOS上的网络是否可用? 回答1 试试这个: unit Network; interface function IsConnected: Boolean; function IsWiFiConnected: Boolean; function IsMobileConnected: Boolean; implementation uses System.SysUtils, Androidapi.JNIBridge, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.JavaTypes, FMX.Helpers.Android, Androidapi.Helpers, Misc; type JConnectivityManager = interface; JNetworkInfo = interface; JNetworkInfoClass = interface(JObjectClass) ['{E92E86E8-0BDE-4D5F-B44E-3148BD63A14C}'] end; [JavaSignature('android/net/NetworkInfo')] JNetworkInfo = interface(JObject) ['{6DF61A40-8D17-4E51-8EF2
  • Delphi XE5 Android。 如何使用PowerManager.WakeLock?(Delphi XE5 Android. How to use PowerManager.WakeLock?)
    问题 我想保持设备开机状态,即使在没有用户活动的情况下,也要避免从内存中卸载应用程序。 有点像服务。 我做了类似如何检查网络是否在Android和iOS(Delphi XE5)上可用的模块,但是当我运行SetWakeLock时系统崩溃了: unit Android.PowerManager; interface function SetWakeLock : boolean; procedure ReleaseWakeLock; implementation uses System.SysUtils, Androidapi.JNI, Androidapi.JNIBridge, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.JavaTypes, FMX.Helpers.Android; type JPowerManager = interface; JWakeLock = interface; JWakeLockClass = interface(JObjectClass) ['{4CF7A13D-15A9-4DEE-8CA7-66600C188CB7}'] end; [JavaSignature('android/os/PowerManager/WakeLock')] JWakeLock = interface
  • Delphi XE5 Android. How to use PowerManager.WakeLock?
    I'd like to keep device on and avoid unloading my application from memory even while there is no user activity. Something like service. I made module like How to check if network is available on Android and iOS ( Delphi XE5 ) but system crushes when I run SetWakeLock: unit Android.PowerManager; interface function SetWakeLock : boolean; procedure ReleaseWakeLock; implementation uses System.SysUtils, Androidapi.JNI, Androidapi.JNIBridge, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.JavaTypes, FMX.Helpers.Android; type JPowerManager = interface; JWakeLock = interface; JWakeLockClass =
  • Android background service in Delphi XE5
    I need to write some service for android, using delphi XE5 (firemonkey). That service need to run in backgroung and periodically read sms inbox, writing it into sqllite DB (sms backup). I know how to read sms and how to write it to DB, but I have no idea how to make app work in background as service. Any ideas? P.S.: Thank you for your answers. P.P.S.: Sorry for my bad english.
  • Accessing Android's SharedPreferences class from Delphi
    I have just started on the Android development path using Delphi XE5, and am trying to build a simple application that needs to be able to persist some entered information (configuration). I have figured out, that the Android class SharedPreferences probably is the easiest way to do this, but I can't figure out how to access this class from Delphi XE5 FMX Mobile. I have tried searching for "SharedPreferences" in the help, but it returns nothing. A search for "Shared Preferences", on the other hand, gives me too much.
  • Delphi XE5中的Google Cloud Messaging?(Google Cloud Messaging in Delphi XE5?)
    问题 我有一个正在考虑移植到Delphi的android应用程序,但是我看不到与GCM交互的方法。 我在想我可能必须在Java中运行GCMBaseIntentService并与delphi共享对象接口? 另外,我正在寻找一种在Delphi Xe5 android应用程序中进行推送通知的方法。 回答1 您可以使用JNI将Java与Delphi交互。 JNI允许您双向调用:Java到Delphi或Delphi到Java。 因此,您可以使用Java类扩展您的Delphi应用程序。 为了在Android上实现您想要的功能,用Java进行操作将是更容易遵循的方法,因为一些可用的示例完全符合您的想法。 看看: 实施推送通知/ Android的Google Cloud Messaging 使用基于云的警报服务的Android *客户端应用 Github Gist-GCMIntentService.java 要连接Java JNI和Delphi,您可以按照详细的步骤进行操作,从而可以在应用程序的前端和后端之间进行顺畅的通信。 如果您决定重用某些代码,请记住要适当感谢作者。 回答2 我让GCM与Delphi一起工作,并制作了一个示例组件来照顾注册和接收GCM消息。 注意:这只是一个粗略的测试代码,我尚未在任何实际应用程序中使用它。 请随意修改和改进,如果发现错误,请发回。 非常感谢Brian
  • Delphi XE5 可以为 Windows 8 RT 和 Windows Phone 8 生成应用程序吗?(Can Delphi XE5 produce apps for Windows 8 RT and Windows Phone 8?)
    问题 是否可以使用 Delphi XE5 或 RAD Studio XE5 为 Windows 8 RT(基于 ARM 的平板电脑)和 Windows Phone 8 创建应用程序,使用与 Android 和 iOS 相同的代码(Firemonkey)? 我在 Embarcadero 的网站上搜索了有关 Windows 开发的内容,但在很大程度上避免提及 Windows 8 RT 和 Windows Phone 8。它指出 您的应用程序将在 Windows 台式机和基于 x86 的平板电脑上运行,这些平板电脑采用英特尔和英特尔凌动硬件,如 Microsoft Surface Professional、惠普、华硕等公司的 Slate 平板电脑,以及宏碁、三星等基于 AMD 处理器的平板电脑。 这是否意味着 Delphi/RAD Studio XE5 不支持 Windows 8 RT 和 Windows Phone 8? 回答1 Delphi XE5 无法生成在 WinRT 或 Win Phone 8 上运行的应用程序。 回答2 正在 Windows ARM/RT、Linux Server、TBD 上完成工作。 看看 Embarcadero RAD Studio 路线图 http://edn.embarcadero.com/article/42544 回答3 为了确认大卫接受的答案
  • 从Delphi访问Android的SharedPreferences类(Accessing Android's SharedPreferences class from Delphi)
    问题 我刚刚开始使用Delphi XE5进行Android开发,并尝试构建一个简单的应用程序,该应用程序必须能够保留一些输入的信息(配置)。 我已经知道,Android类SharedPreferences可能是最简单的方法,但是我无法弄清楚如何从Delphi XE5 FMX Mobile访问此类。 我尝试在帮助中搜索“ SharedPreferences”,但未返回任何内容。 另一方面,搜索“共享首选项”给了我太多。 回答1 简而言之,将所需的API单元添加到uses子句中-您的案例中的关键是AndroidApi.Jni.JavaTypes , AndroidApi.Jni.App和AndroidApi.Jni.GraphicsContentViewText以及FMX.Helpers.Android进行粘合代码-就像在Java中一样调用它。 Java类作为带有初始J的接口类型公开; 实际上,Android API大量使用嵌套类,并且由于Delphi不支持嵌套接口类型,因此它们成为ParentClassName_ChildClassName: var Prefs: JSharedPreferences; Editor: JSharedPreferences_Editor; I: Integer; F: Single; S: string; begin Prefs :=
  • How to check if network is available on Android and iOS ( Delphi XE5 )
    How to check if network is available on Android and iOS?
  • Google Cloud Messaging in Delphi XE5?
    I've got an android app that I am thinking about porting to Delphi but I can't see a way to interface with GCM. I am thinking I would possibly have to run the GCMBaseIntentService in java and interface with the delphi shared object? Alternatively, I am looking for a way to do push notifications in a Delphi Xe5 android app.
  • Can Delphi XE5 produce apps for Windows 8 RT and Windows Phone 8?
    Is it possible to use Delphi XE5 or RAD Studio XE5 to create apps for Windows 8 RT (ARM based tablets) and Windows Phone 8, using the same code (Firemonkey) as for Android and iOS? I searched Embarcadero's website on windows development but it goes a long way to avoid mentioning Windows 8 RT and Windows Phone 8. It states that Your apps will run on Windows desktops and x86 based tablets with Intel and Intel Atom hardware such as Microsoft Surface Professional, Slate tablets from HP, Asus and others, as well as AMD processor based tablets from Acer, Samsung and more. Does this mean that Windows
  • Delphi - 如何使用 iPhone 作为图片源使用 OpenDialog 获取目录(Delphi - How to get Directory with OpenDialog using iPhone as a picture source)
    问题 我有一个 Delphi 应用程序 (D2010),它允许用户通过 OpenDialog 选择一个 JPG 文件。 当我从普通的 Windows 目录中选择文件时,我的 TOpenDialog.Filename 包含文件的完整路径,并且我的代码有效。 我遇到的问题是用户经常将文件电话复制到手机。 当用户插入手机,运行我的代码时,TOpenDialog 显示手机上的文件,用户选择正确的 jpg 文件,但 TOenDialog.Filename 不包含文件的路径(只有文件名),所以我的程序找不到该文件。 对于CAMERAS 和CELL PHONES,图片目录是DCIM 目录。 无论出于何种原因,Windows 7 以及可能所有其他系统都不会为此目录提供驱动器号。 因此 TOpenDialog 只返回文件名,而不是完整的路径名。 这意味着我无法复制文件,因为我没有完整的路径名。 简而言之,我的问题是:当路径是手机(在我的情况下是 iPhone 5)上的存储区域时,如何使用 TOpenDialog 获取完整路径名。 XE5 有一个名为 GetCameraPath 的例程,但 D2010 没有。