Xamarin iOS swap image in bundle at runtime - ios

I want to allow my app to download images from the web to be placed in /images and then displayed in the UI - this is to allow branding specific images to be downloaded for a multitenant app.
The app downloads the image fine and places the image into the /Images folder
However when trying to load the image using UIImage.FromFile it always returns null - even though I know full well the image is there!
I know UIImage.FromBundle caches stuff so I chose to use FromFile but this doesn't seem to work?!
Is there something I need to do to make this work? Or am I pushing my luck a little?
I am using the following to create the file path:
public static UIImage SafeClaim_Logo = UIImage.FromFile(NSBundle.MainBundle.BundlePath +"/Images/Logo.png");
The following is the code I use to download and save the file - the file path from the above is the same below when I inspect it
HttpClient client = new HttpClient ();
var clientResponse = await client.GetByteArrayAsync(url);
using (FileStream fs = new FileStream(NSBundle.MainBundle.BundlePath + path, FileMode.OpenOrCreate))
{
var bytes = clientResponse;
fs.Write(bytes, 0, bytes.Length);
}

The app bundle is read-only so you can't change or add something in there at runtime.
All content created at runtime should be stored in your documents or cache folders.
You can get the documents folder by calling:
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)

One good place to store this kind of files is the Library/ folder. On iOS 7 you can access it using:
var libraryFolderPath = Path.GetFullPath(
Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments), "..", "Library"));
On iOS 8:
var url = NSFileManager.DefaultManager.GetUrls (
NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomain.User) [0];
var libraryFolderPath = url.Path;
The reason is explained by Xamarin documentation:
The Library directory is a good place to store files that are not
created directly by the user, such as databases or other
application-generated files. The contents of this directory are never
exposed to the user via iTunes.
You can create your own subdirectories in Library; however, there are
already some system-created directories here that you should be aware
of, including Preferences and Caches.
The contents of this directory (except for the Caches subdirectory)
are backed up by iTunes. Custom directories that you create in Library
will be backed up.
If you need to enable iTunes file sharing and expose the content of the Documents/ folder, your files are not visible to the user.

Related

ios sqlite error : attempt to write a read-only database

I made the iOS app unity.
It also successfully selected data from sqlite.
But when I insert, the error below appears.
mono.data.sqlite.sqliteexception (0x80004005): attempt to write a read-only database
The path to the DB file is here.
string filepath = Application.dataPath + "/Raw/Data.db";
if (!File.Exists(filepath))
{
File.Copy(Application.streamingAssetsPath + "/Raw/Data.db", filepath);
}
I wonder if I should set write permissions or change the path of the file.
What should I do if I have to grant write permission?
If I have to change the route, where should I go?
In the official documentation you have this:
On many platforms, the streaming assets folder location is read-only; you can not modify or write new files there at runtime. Use Application.persistentDataPath for a folder location that is writable.
Solution: Use Application.persistentDataPath instead of streaming asset folder.

Show images from perticular folder in iOS

I am using https://pub.dev/packages/flutter_image_gallery to show images stored in the particular folder but it is showing all images from the gallery is there any way that I can use it to show from a particular folder only
If you want specific directory location image then use ext_storage package. You can get all the files of the specific folder. You just have to separate it by extension. Please look at the code below so you can get idea. the code is same as shown in library.
void _example1() async {
var path = await ExtStorage.getExternalStorageDirectory();
print(path); // /storage/emulated/0
}

How to set path to picture in folder in device in android appcelerator app

So I have app where I want to let users to share screenshot of score to facebook etc... I'm using SocialShare widget. In documentation it says to set path to image like this: "image:fileToShare.nativePath", but I'm not really sure how to set it. Another problem is that I need to share picture that has always different name, it saves screenshots with names like tia7828157.png,tia107997596.png... in folder in device internal memory in pictures/enigmania/ I'm new to appcelerator, so I dont know if there is something like wildcard I could use for this? Thanks for any help.
This is my code so far which I know is wrong, I know the widget works because it shares text without problem:
function shareTextWidget(e){
// share text status
var socialWidget=Alloy.createWidget('com.alcoapps.socialshare');
socialWidget.share({status:"Enigmania kvíz",androidDialogTitle:"hoho",image:test.png/pictures/enigmania});
}
You should use Ti.Filesystem class methods/properties to get the path of any file located on internal or external storage.
Also aware of the permissions of reading storage on Android 6+. Use Storage Permissions before accessing any file on Android 6+.
Simple code snippet to create a directory on internal storage at this location: pictures/enigmania and then write an image file of captured view in this directory.
function shareTextWidget(e){
var directory = Ti.Filesystem.getFile(Ti.Filesystem.externalStorageDirectory, 'pictures/enigmania');
!directory.exists() && directory.createDirectory();
var fileToShare = Ti.Filesystem.getFile(directory.resolve(), 'screen.jpg');
fileToShare.write($.SCREENSHOT_VIEW.toImage()); // write the blob image to created file
var socialWidget=Alloy.createWidget('com.alcoapps.socialshare');
socialWidget.share({status:"Enigmania kvíz",androidDialogTitle:"hoho",image:fileToShare.nativePath});
}
This code should work without any issues.
Note that $.SCREENSHOT_VIEW is the View ID for which you will take screenshot, so it depends on you how you maintain your View positions in order to capture correct screenshot, but point is to use Ti.UI.View toImage() method to capture the screenshot of particular view.
Let me know if this works for you or not, else we can look into other methods by getting your exact requirements. Good Luck!!!!

Permanent file directory in Xcode

In the documents directory for my app, I have a file Q1.dat which I use in my program. I access it through the path:
func createArrayPath () -> String? {
if let docsPath: String = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last {
return ((docsPath as NSString).stringByAppendingPathComponent("Q1") as NSString).stringByAppendingPathExtension("dat")
}
return nil
}
When I run the program on a different device however, a different documents directory is created, and the file is no longer present. Is there a place I can put the file so that I can always access it no matter what device I am running on?
The Documents directory is meant for data created by the user.
It sounds like you want to bundle a resource with your application. You can do this by simply dragging the file into Xcode, which will automatically set it up to be copied into your app bundle, and you can find it using URLForResource(_:withExtension:).
If the file is very large, you might want it to be downloaded separately from the main app. For this you can use the new On-Demand Resources feature.

How to Reduce AIR app file size?

I've uploaded an AIR-built .ipa file to Apple. From Apple: "The app binary listed below was 8 MB when you submitted it, but will be 20 MB once processed for the App Store"
So I'm trying to trim it. I've gotten rid of all unused .as classes and all unused assets. Does anyone have any clever way of reducing file size further? One way I thought of is this:
If in class A I have:
[Embed(source="assets/newButtons/purple/purpleHomeSmall.png")]
and then I re-embed it in class B with the same code, does that mean it is embedded twice with twice the file size? If so, how would I embed it in one class but have access to it in other classes?
Edit: I've discovered that if you have assets in your project that you don't use, the compiler STILL ADDS them. So you have to get rid of them before making a release build.
Instead of embedding the source why not just load it from URI at runtime?
Create an abstract bitmap class that builds a bitmap from the URI and places it on stage.
This way you can ensure the bitmap is only stored once and is loaded lazily.
Update
you can add a folder in the air for iOS settings dialog.
Place the images you want and then:
var imageLoader:Loader = new Loader();
var theURL:String = "string to your uri can be local or web";
var imageRequest = new URLRequest(theURL);
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
imageLoader.load(imageRequest);
function onComplete(evt:Event)
{
addChild(imageLoader.content);
}
One option i have used is to compile the ipa with only the most necessary assets and then when the user first initializes the app have it download and store further assets in the application storage (this could be done with a single zip-file and the FZip class: http://codeazur.com.br/lab/fzip/)
This way the app only has to download the assets once (on first run) and they are immediately available in the future from the local system.
Instead of embedding images in each source file, what I do is create a class in the default package, where I place all my images as static public variables. Something like this:
package {
public class Icons{
[Embed(source="assets/icon1.png")] [Bindable] static public var icon1:Class;
}
}
Whenever I need the icon, I just use Icons.icon1.
You cannot ! Your app will be more than 20Mb and its like that. Because the need of Adobe AIR runtime, embedded in your IPA.
So its useless to try to optimize your code, asset .... should chase adobe for this job !
My application: prestadget is 800Ko as APK (w/o AIR runtime) but 21Mo as IPA ;-( same code

Resources