I am trying to exchange files between a .Net Desktop App and a Xamarin.Forms Android app. I really had trouble getting resources and help, so I want this question to also wrap some stuff up - for other interested users (not only of Xamarin Forms)
So far I got to read files and folders in .Net C# using
Christophe Geers' Blog and Fun with MTP and because writing did not work on all of my devices Windows File Stuff by Flauschig
On Xamarin.Forms side of the wall I first stumbled over Xamarin doc and A lib to store from pcl code and also Plugin.Permissions.
With all these sources above I was able to get reading and writing on the Android (Samsung A5, Android 6.0) to work.
With this description on filestructure I thought the following Code will always get a valid path:
public string GetExternalFolder()
{
GetPermission();
var externalFolder = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, "Android", "data", "com.exampledom.appname", "files");
if (!Directory.Exists(externalFolder))
CreateFolderStructure();
return externalFolder;
}
GetPermission() is taken from Plugin.Permissions and will throw exception if permission is not given.
CreateFolderStructure() is using pcl.storage - and looks like this.
private async void CreateFolderStructure()
{
try
{
IFolder rootFolder = await FileSystem.Current.GetFolderFromPathAsync(Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path));
var subpaths = new[] {"Android", "data", "com.exampledom.appname", "files"};
foreach (var dir in subpaths)
{
if (!string.IsNullOrEmpty(dir))
rootFolder = await rootFolder.CreateFolderAsync(dir, CreationCollisionOption.OpenIfExists);
}
Log("Folder structure created!");
}
catch (Exception e)
{
Log("Folder structure cannot be created!");
Console.WriteLine("Failed to log! " + e.Message);
}
}
Ok, now for the question:
The Folder that is created by this Method is only created on one device I tested on (proof of concept) - all others (eg Samsung A3, Android 6.0) nothing happens(proof of helpless developer). A reboot is not the solution.
Also on the device this works on - the permission is requested as expected. There is no permission request on the other devices.
Why is the desired folder not created during install? It seems all other apps do have such a folder 'Android/data/com.exampledom.appname/files'.
What am I missing? It seems overly hard to import/export to android.
#smack Does CreationCollisionOptions.OpenIfExists really create a folder? I don't think so. Is there not CreateIfNotExists enum?
Related
i have tried running cordova media plugin in both kitkat and lollipop but it shows no response.
Not even the 3rd parameter for error's function is running.
I have also read almost every article or question about this problem and tried every way i could but nothing worked.
All i finally concluded was that this plugin is not fully supported in android versions above 4.1
I have tried:
<script>
document.body.onload="ready()";
function ready()
{
document.addEventListener("deviceready",function() {
var src;
// src's value
var med=new Media(src,
function() {
alert("success");
},
function(e)
{
alert("failed code: "+e);
});
med.play();
med.release();},false);
}
</script>
here is what i have tried replacing with //src's value
src = 'cdvfile://audio.mp3';
src = 'file:///android_asset/www/audio.mp3';
src = "cdvfile:///android_asset/www/audio.mp3";
src = "audio.mp3";
even after that stupid conclusion i wrote about up there, i still am doubtful that how it still runs on some devices with same os. So, any ideas of making audio files play in cordova app?
MORE INFO:
1>My project structure
appName
|___www
|___[+]css
|___[+]js
|___index.html
|___[+]img
|___audio.mp3
2>I am targeting 6.3.0 marshmallow 😋
Media definitely works for me on marshmallow - albeit I use wav files rather than mp3. I use
audioFail = loadAudio('sounds/no.wav'); where the file is stored in www/sounds
The media constructor is asynchronous but your code uses med immediately after issuing the call to the constructor - have you confirmed that med exists and is defined before you try to call med.play()?
I'm using this nu-get package to stream mp3 url in a Xamarin Android project:
https://github.com/martijn00/XamarinMediaManager
I followed the instructions in the link up there... and it shows the music playing in the notification bar but it is not working (no sound and it's not even starting the song).
Code snippet:
clickButton.Click += (sender, args) =>
{
ClickButtonEvent();
};
private static async void ClickButtonEvent()
{
await CrossMediaManager.Current.Play("http://www.montemagno.com/sample.mp3");
}
I built the sample included in the link, and I got the same result from their sample. Also deployed on real device too, same result!
Image:
Am I missing something ?
Or is the library broken ?
I ran into this using Android Emulator on Hyper-v. It turns out that the network is set to internal. So the http://www.montemagno.com/sample.mp3 could not be found. My workaround:
Hyper-v -> Virtual Switch Manager, add an external network.
Hyper-v -> Virtual Machines->Settings, add new hardware->Network adapter and set to external network.
"Visual Studio Emulator for Android" desktop app, launch phone vm,
in Visual Studio, deploy and run app.
Sound should work from external source now.
Permissions maybe? In the project site it states that for Android:
You must request AccessWifiState, Internet, MediaContentControl and
WakeLock permissions
By default example use ExoPlayerAudioService.
There are issue with url escape in ExoPlayerAudioService.GetSource method
private IMediaSource GetSource(string url)
{
string escapedUrl = Uri.EscapeDataString(url);
var uri = Android.Net.Uri.Parse(escapedUrl);
var factory = URLUtil.IsHttpUrl(escapedUrl) || URLUtil.IsHttpsUrl(escapedUrl) ? GetHttpFactory() : new FileDataSourceFactory();
var extractorFactory = new DefaultExtractorsFactory();
return new ExtractorMediaSource(uri
, factory
, extractorFactory, null, this);
}
string escapedUrl = Uri.EscapeDataString(url);
I.E. http://example.com/path_to_audio.mp3 will be escaped to "http%3A%2F%2Fexample.com%2Fpath_to_audio.mp3" as result HTTP error.
To fix just skip url escape.
Anybody success to use the plugin cordovaFile & cordovaFileTransfer?
I have failed to understand and failed miserably execution. Case wants to make the upload and download controller. Each tested via the browser, it always appears File / FileTransfer is not defined in Firebug. When I made to console.log as:
console.log($cordovaFile); or
console.log($cordovaFileTransfer); or
console.log($cordovaFileTransfer.download); or
console.log($cordovaFileTransfer.upload);
Its return true, form of the {object}.
But when I call their methods included parameters, for example:
$cordovaFileTransfer.download (urlServer, fileTarget, {}, true);
Direct emerge error: FileTransfer is not defined.
I tried to move the download function to the Service, and then Controller call the function (the umpteenth time search results on google). The result is just the same, the above error.
Because there are user in some forum said should / could only be tested through the device, finally I try to upload ionic.io & I sync via APL ionic view on my Smartphone. But the result is NOTHING.
I tried to improvise a little, try method checkDir / checkFile as follows:
.controller('PhotoCtrl', function($scope, $cordovaFile) {
$scope.downpic = function(){
$cordovaFile.checkDir("/sdcard/storage/emulated/0/").then(function(result){
alert("wow");
}, function(err){
alert("eror");
});
}
})
It turns out alerts that appear "error", I try mutually value directory is as follows:
file///sdcard/storage/emulated/0/
file///storage/emulated/0/
/storage/emulated/0/
Just the same error alerts, the chain problem. My question :
What is the application of ionic cordova can access the internal
storage? (I only have the Mobile Internal Storage, without External
Storage);
I was looking for information about AndroidManifest.xml
uses-permission, the permission is only for external storage. Are
there any other analysis?
Please help, really newbie
Finally, I just got the clear solution from the link below :
https://www.thepolyglotdeveloper.com/2014/09/manage-files-in-android-and-ios-using-ionicframework/
I'm developing Phonegap application (using AngularJs+Bootstrap) which supports iOS and Android. We had to maintain two code bases so far but its the same functionalities, only few differences like below.
Application name/icons are different
Main url is different for web-service calls
Ex :
PhoneGap App X : call http://abc/xappinfo weservice, use x_icon_app.png
(This has to build for both iOS and Android which i have no issue)
PhoneGap App Y : call http://xyz/yappinfo weservice, use y_icon_app.png and other UI elements for mobile skin
(This also has to build for both iOS and Android)
Both PhoneGap App X and Y uses same code for business logics.
I would like to maintain one code base for both apps since there only few differences. Is there any way I could achieve this or simplify my development effort?
I had a similar situation. I placed all my app folders in a single folder and placed the following code in a file in the root folder called: persist.js. Its purpose is to persist file changes across all of the different apps keeping the same path. It is a little manual, but works...
var fs = require('fs');
var chalk = require('chalk');
var argv = require('minimist')(process.argv.slice(2));
var file = argv.f;
var apps = [
'app_folder_1',
'app_folder_2',
'app_folder_3',
'app_folder_4',
'app_folder_5',
];
if(file){
if (fs.existsSync(file)) {
console.log(chalk.blue('Found source file'));
var fileWithoutApp = file.substring(file.indexOf('/'));
apps.map(app => {
fs.writeFileSync(app + fileWithoutApp, fs.readFileSync(file));
console.log(chalk.green(`File copied to: ${app + fileWithoutApp}`))
});
} else {
console.log(chalk.red('File does not exist'));
}
} else {
console.log(chalk.red('No file specified'));
}
After changes are made to a file within any of the project folders just call the following from the command line:
node persist -f [relative path to your file that has changes]
This will persist the change across all projects. Like I said, a little manual... but effective :)
When u use cordova or ionic + angularjs you can compile application for both device this is more simple you like complication !!
Is there a way to open one app from another app in Air? Example: I open app A which contains a button that opens app B when clicked. Suppose both A and B are separated apps that are installed in the device and that this device could be a PlayBook, an Ipad or an Android tablet.
Thanks.
You'd have to go the Air Native Extension(ANE) route. Either create one ANE solution for iOS and Android each, or one ANE that abtracts the functionality into one solution. How to launch app A from app B on Android is not the same as on iOS. See this answer in SO.
To implement it on Android, you'd wraps the native Android Java solution in a ANE. The native Java code uses the package name of app B to launch app B from app A:
Intent intent = getPackageManager().getLaunchIntentForPackage("com.yourdoman.yourapp");
startActivity(intent);
Here is a video tutorial on how to launch an Activity through an ANE which you can build on to create your ANE. You'd have to tailor the solution to launch by domain instead of Activity.
Since I really don't know the specifics of what you are trying to do, I think I should point you here: http://www.riaspace.com/2011/08/defining-custom-url-schemes-for-your-air-mobile-applications/ It is the best answer to the question that I am aware of.
private function getHostName() : void
{
if (NativeProcess.isSupported)
{
var OS : String = Capabilities.os.toLocaleLowerCase();
var file : File;
if (OS.indexOf('win') > -1)
{
// Executable in windows
file = new File('C:\\Windows\\System32\\hostname.exe');
}
else if (OS.indexOf('mac') > -1 )
{
// Executable in mac
}
else if (OS.indexOf('linux'))
{
// Executable in linux
}
var nativeProcessStartupInfo : NativeProcessStartupInfo = new NativeProcessStartupInfo();
nativeProcessStartupInfo.executable = file;
var process : NativeProcess = new NativeProcess();
process.addEventListener(NativeProcessExitEvent.EXIT, onExitError);
process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutput);
process.start(nativeProcessStartupInfo);
process.closeInput();
}
}
private function onOutput(event : ProgressEvent) : void
{
var strHelper : StringHelper = new StringHelper();
formStationID.text = event.target.standardOutput.readUTFBytes(event.target.standardOutput.bytesAvailable);
formStationID.text = strHelper.trimBack(formStationID.text, "\n");
formStationID.text = strHelper.trimBack(formStationID.text, "\r");
}
This code gets the workstation name. I have heard this can be done on IOS and Android, but I haven't found any proof of that yet.