I am needing to have my cordova wrapped html show a picture and run a video file located off the root of the external SD. There did not seem to be a place to ask these questions on the git hub for the cordova-plugin-file.
A) I am not sure I understand what path to use in 2 B&C below in order to accomplish this if the files are in those two sub directories off the root?
B) Are ALL those values in 3 B necessary if all I need is access to the ext SD?
Here is what I know from the documentation so far ... but obviously I don't have it all correct because I get the error (see below)
1) Set up environment from CMD line
cordova create MyApp
cd /MyApp
cordova platform add android@latest
cordova plugin add cordova-plugin-whitelist
cordova plugin add cordova-plugin-file
corddova build android (after step 3 below)
2) Add these to index.html
A) cdvfile: scheme to Content-Security-Policy meta tag of the index page, e.g.:
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap:cdvfile:https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src
B) <img src="cdvfile:///img/logo.png" />
C) <p><a href="cdvfile://video/MyVideo.mp4">Play video</a></p>
3) Add these to config.xml
A) <access origin="cdvfile://*" />
B) <preference name="AndroidExtraFilesystems" value="files,files-external,documents,sdcard,cache,cache-external,assets,root" />
The error I get on the Android when clicking on the video link is ...
net::ERR_UNKNOWN_URL_SCHEME (cdvfile:video/0001_a1.mp4)
=========== EDIT #1
Now trying recommendation by @DaveAlden ... using plugin called [cordova.plugins.diagnostic][2]
with this configuration to locate root path on ExtSD to play video BUT get the error (see below) ...
config.xml
<preference name="android-minSdkVersion" value="14" />
<preference name="android-targetSdkVersion" value="14" />
<preference name="android-maxSdkVersion" value="25" />
<plugin name="cordova-plugin-whitelist" spec="1" />
<plugin name="cordova.plugins.diagnostic" />
Index.html
<body>
<!-- Set up path to ExtSD on Android -->
<script>
function getSdRefAndEmbed(){
cordova.plugins.diagnostic.getExternalSdCardDetails(function(details){
details.forEach(function(detail){
if(detail.type === "root"){
cordova.file.externalSdCardRoot = detail.filePath;
embedMedia();
}
});
}, function(error){
console.error(error);
});
}
function embedMedia(){
$('.extSdVideo').each(function(){
$(this).attr('href', cordova.file.externalSdCardRoot + $(this).attr('href'));
});
}
$(document).on('deviceready', getSdRefAndEmbed);
$(document).on('pageinit', embedMedia);
</script>
<!-- Play video file -->
<a class="extSdVideo" href="video/0001_a1.mp4" id="0001_a1"> a1 </a>
</body>
Application Error
net::ERR_FILE_NOT_FOUND (file:///android_assest/www/HHR/hhr-cm_cameroon-cm1-fra-spa/hhr/hhr-cm_cameroon-cm1-fra-spa/video/0001_a1.mp4
Tried placing the 0001_a1.mp4
in either of these two directories...
extSDRoot/video/0001_a1.mp4
and/or
extSDRoot/www/HHR/hhr-cm_cameroon-cm1-fra-spa/hhr/hhr-cm_cameroon-cm1-fra-spa/video/0001_a1.mp4
=================== EDIT #2
@DaveAlden Suggested trying these three things...
1) Put console.dir(details)
inside of getExternalSdCardDetails()
to see what native paths the plugin is finding.
RESULT: it gives the same path in the error message
Application Error
net::ERR_FILE_NOT_FOUND
(file:///android_asset/www/hhr/cm_cameroon-cm1-fra-spa/0001_a1.mp4)
2) Try the example project (https://github.com/dpa99c/cordova-diagnostic-plugin-example) on the same device to see if the ext SD example works.
RESULT 1: The build for the example project failed...
BUILD FAILED Total time: 47.426 secs Error: cmd: Command failed with exit code 1 Error output: F:\DIAGNOSTIC_WORKING\cordova-diagnostic-plugin-example\platforms\android\build\ intermediates\res\merged\debug\values-v24\values-v24.xml:3: AAPT: Error retrievi ng parent for item: No resource found that matches the given name 'android:TextA ppearance.Material.Widget.Button.Borderless.Colored'.
@DaveAlden response to the Build Fail...
You have missing/outdated Android SDK components in your build environment and/or are using an outdated version of cordova-android platform. See documentation (https://github.com/dpa99c/cordova-diagnostic-plugin#building-for-android) and this issue (https://github.com/dpa99c/cordova-diagnostic-plugin/issues/161).
My Actions:
I checked the Android SDK Manager to see that all API levels were on the same level for the required products by running this command
C:> Android -v
Android SDK Tool 25.2.5
SDK platform 25
Android Support Repository 46
Google Play services 39
Google Repository 45
I ran this command...
cordova platform check android
Got this result...
F:\DIAGNOSTIC_WORKING\cordova-diagnostic-plugin-example>cordova platform check android
Subproject Path: CordovaLib
android @ 6.1.2; current did not install, and thus its version cannot be determined
Why do I get this "current did not install"? Could this be the issue why the diagnostic plugin is not finding the correct path for the extSD?
I ran this command...
cordova platform rm android && cordova platform add android@latest && cordova build android
Now the Build Succeeded for Example Project!
See screen shot of the example diagnostic app showing path to the extSD. This path looks very different from the path I am getting when I run the diagnostic plugin in my app.
Note the button "Write External SD File" did not write anything when pressed. I checked with my file manager.
The path given for the Example Project is very different for the path that the diagnostic plugin gives for my app (see mine below). These results were from the same Galaxy S7.
net::ERR_FILE_NOT_FOUND (file:///android_assest/www/HHR/hhr-cm_cameroon-cm1-fra-spa/hhr/hhr-cm_cameroon-cm1-fra-spa/video/0001_a1.mp4
I ran this command for my app but no change ...
cordova platform rm android && cordova platform add android@latest && cordova build android
3) @DaveAlden suggested running a debug using Chrome... I'll do that next.
============= EDIT 3 SUCCESSFULLY played video from extSD using cordova-diagnostic-plugin
Here's how...
The final hurdle was that because I have an Android 6+ phone I had to also add a function to check for run time permission to read the extSD. The code kept bombing with the error show in Edit #2 (see above) like it was trying to see an internal path. Once I added the function to check for run time permission it finally gave the correct external path. Hint ... it is not enough to just provide the permission in the manifest. You can read about it here. Thanks @DaveAlden for your example project!
https://github.com/dpa99c/cordova-diagnostic-plugin-android-runtime-example
Android runtime permissions
Android 6 / API 23 introduces the concept of runtime permissions. Similar to >iOS, certain "dangerous" permissions must be requested at runtime in addition >to being listed in the Android manifest.
Runtime permissions only apply if the device/emulator the app is running on has >Android 6.0 or above AND the app is built using API 23 or higher. For Cordova, >this means using the Cordova Android platform version 5.0.0 or above. If the >app is built with version 4.x or below (API 22 or below), runtime permissions >do not apply - all permissions are granted at installation time.
Add to Config.xml
<access origin="*" />
<plugin name="cordova-plugin-whitelist" version="*" />
<plugin name="cordova.plugins.diagnostic" version="*" />
<plugin name="cordova-plugin-file" version="*" />
<preference name="android-minSdkVersion" value="21" />
<preference name="android-targetSdkVersion" value="23" />
<config-file target="AndroidManifest.xml" parent="/*">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Thanks to @DaveAlden for this code... I only added the function to check the run time read permission. Dave you should just add this code for reading media files from the extSD to your project example so you don't have to help the next person as much as you did me. :)
Add to Index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src * gap://ready file:; style-src 'self' 'unsafe-inline'; img-src * 'self' data:; script-src * 'unsafe-inline' 'unsafe-eval'">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<h3>Play video and img file</h3>
<img class="extSdImg" src="img/image1.png"/>
<img class="extSdImg" src="img/image2.png"/>
<p>
<a class="extSdVideo" href="video/video1.mp4">Play video</a>
</p>
<p>
<a class="extSdVideo" href="video/video2.mp4">Play video</a>
</p>
</body>
</html>
Add to Index.js
function authorizerequestExtSD() {
cordova.plugins.diagnostic.requestExternalStorageAuthorization(function(status){
console.log("Successfully requested external storage authorization: authorization was " + status);
checkState();
getSdRefAndEmbed();
}, function(error){
console.error(error);
});
}
function getSdRefAndEmbed(){
cordova.plugins.diagnostic.getExternalSdCardDetails(function(details){
details.forEach(function(detail){
if(detail.type === "root"){
cordova.file.externalSdCardRoot = detail.filePath;
embedMedia();
}
});
}, function(error){
console.error(error);
});
}
function embedMedia(){
$('.extSdImg').each(function(){
$(this).attr('src', cordova.file.externalSdCardRoot + $(this).attr('src'));
});
$('.extSdVideo').each(function(){
$(this).attr('href', cordova.file.externalSdCardRoot + $(this).attr('href'));
});
}
$(document).on('deviceready', authorizerequestExtSD);
$(document).on('pageinit', embedMedia);
Add local file copy of jQuery (found one in this project https://github.com/dpa99c/cordova-diagnostic-plugin-example):
jquery-2.1.3.min.js
Your approach is not going to work: cdvfile://
is an internal pseudo-protocol defined by cordova where the first part of the path defines an internal reference point (cdvfile://localhost/persistent|temporary|another-fs-root*/path/to/file
) whereas 2B and 2C are defining paths as if relative to the root of the external SD card root.
Note that cordova-plugin-media will not help you, since it's only for playing audio and does not itself resolve file locations.
If your media files are on an external removable SD card (e.g. in Samsung Galaxy devices), cordova-plugin-file
does not provide a reference to access this location. The "external" references used by cordova-plugin-file (e.g. cordova.file.externalRootDirectory
) actually point to an internal memory location - /scard/
. This is because not all devices have removable external SD cards (e.g. Google Nexus) so /sdcard
is an "emulated" storage location which is guaranteed to exist on all Android devices.
If you wish to read files from the external removable SD card, you can do so using cordova-diagnostic-plugin to obtain a valid filepath reference to the external SD card root. Note that this will need to by done dynamically in JS as opposed to hardcoding static paths in HTML:
index.html
<body>
<img class="extSdImg" src="img/image1.png"/>
<img class="extSdImg" src="img/image2.png"/>
<p><a class="extSdVideo" href="video/video1.mp4">Play video</a></p>
<p><a class="extSdVideo" href="video/video2.mp4">Play video</a></p>
</body>
index.js
function getSdRefAndEmbed(){
cordova.plugins.diagnostic.getExternalSdCardDetails(function(details){
details.forEach(function(detail){
if(detail.type === "root"){
cordova.file.externalSdCardRoot = detail.filePath;
embedMedia();
}
});
}, function(error){
console.error(error);
});
}
function embedMedia(){
$('.extSdImg').each(function(){
$(this).attr('src', cordova.file.externalSdCardRoot + $(this).attr('src'));
});
$('.extSdVideo').each(function(){
$(this).attr('href', cordova.file.externalSdCardRoot + $(this).attr('href'));
});
}
$(document).on('deviceready', getSdRefAndEmbed);
$(document).on('pageinit', embedMedia);