Multiple Firebase Storage Buckets in One App - firebase-storage

Is it possible for one app to use multiple Firebase Storage buckets? Since we need to configure an app upon initialization to use a single bucket, I'm a bit confused about the value of having multi-bucket functionality.

I have had the same situation. This worked for me. Hope it can help someone else too :)
// Add your bucket name here which is not in your GoogleService-info.plist file for your current app.
let storage = Storage.storage(url: "gs://your.storageBucketname.here")
let gsReference = storage.reference(forURL: firestoreLink)

from: https://firebase.google.com/docs/storage/web/start#use_multiple_storage_buckets
// Get a non-default Storage bucket
var storage = firebase.app().storage("gs://my-custom-bucket");

Related

Implementing Sharing with NSPersistentCloudKitContainer in SwiftUI

Is it possible?
I've got a new iOS 14 app set up with Core Data and Cloudkit. I had to make a few changes to my Persistence.swift file to get it working but it's working without a hitch.
I'm interested in implementing sharing with other iCloud Users, but a lot of the documentation is out of date and confusing and it seems like it might not have been possible at one point but it is now?
I think the first step is to make my database shared? I'm adding the following line to my Persistence.swift file
container.persistentStoreDescriptions.first!.cloudKitContainerOptions?.databaseScope = .shared
(Here's the whole thing):
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentCloudKitContainer
init(inMemory: Bool = false) {
container = NSPersistentCloudKitContainer(name: "Shopmatic")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
container.persistentStoreDescriptions.first!.cloudKitContainerOptions?.databaseScope = .shared
}
}
but when I run the app I get the following error
Thread 1: "CKDatabaseScopeShared is not supported with NSPersistentCloudKitContainer"
Which is not encouraging, but maybe it's possible to implement sharing with a public database scope?
I'm not really sure what the next steps are? Implementing my own NSPersistentContainer that both syncs to cloudkit and allows sharing?
I believe the answer is no based on this thread on the Apple dev forums (I'm MasonAndMuse there), but there's one Apple engineer in there who was saying yes but wouldn't elaborate. I stopped trying soon after, not finding any way around the opaque nature of the system as it is now. Nothing I've seen indicates someone else has gotten it working but I haven't looked very closely after giving up 8 months ago. Of course there might be a way - I'd love to be proven wrong!
I assume they introduce sharing in iOS 15, but that's not very helpful now... Too bad because it's so close now and it will save SO much time if/when they add it in...
The Apple engineer's answer in the forum reads quite clearly to me:
NSPersistantCloudKitContainer does not support sharing!
You need to implement CloudKit sharing through CK APIs.
I have not implemented such a feature yet, but I would approach it like this:
Get the NSPersistantCloudKitContainer implementation working.
Implement CloudKit sharing on the same container.
Start passing specific records from NSPersistantCloudKitContainer into the sharing feature implemented in step 2.
To access the shared Cloudkit database with CKDatabase.Scope = shared:
If this is the NSPersistentCloudKitContainer
:
container = NSPersistentCloudKitContainer(name: "AppName")
I would try to access the shared DB of this container like so
:
let myAppsCloudKitContainer = CKContainer(identifier: "iCloud.com.name.AppName")
let myContainersSharedDatabase = myAppsCloudKitContainer.database(with: .shared)
To access data from NSPersistantCloudKitContainer for use in the CloudKit sharing feature use NSPersistantCloudKitContainer instance method
record(for managedObjectID: NSManagedObjectID)
(as of macOS 11 / Xcode 12)

Getting an error "Reseller channel 2c95500b-ea86-4b13-8bb5-b2f0c2fa8200 is invalid." when I try to create a cloud object storage

I created the watson service and went to create a new project. It expects me to add Cloud Object Storage. When I chose the Lite option and press create I get this error "Reseller channel 2c95500b-ea86-4b13-8bb5-b2f0c2fa8200 is invalid."
My goal here is to setup the Watson service in order to play with Visual Recognition dk service. But I am stuck at this stage.
Can someone help with some suggestion of what else can I try or what I might be doing wrong?
Thanks!
I also struggled with this a few minutes ago.
And Cloud Object Storage link at the bottom of the page under Choose project options won't help,
but i found another solution that works for me
Go to https://www.ibm.com/cloud/object-storage/pricing
and click Order IBM Cloud Object Storage at bottom of the page
I hope this can solve your problem

How do I retrieve a list of my downloaded offline map packs using Mabox and Swift?

I am wanting to add offline map functionality to an iOS app build using Swift and Mapbox. There is great documentation and examples for downloading a map region pack, but am having a difficult time figuring out how to retrieve a list of offline packs. Their documentation here gives these instructions on how to receive:
"To detect when the shared offline storage object has finished loading its packs property, observe KVO change notifications on the packs key path. The initial load results in an NSKeyValueChangeSetting change."
But I am having a difficult time find any examples or explanations as to what that means. Any help would be greatly appreciated!
An array of all known offline packs can be retrieved using the .packs attribute of the MGLOfflineStorage class. Like so:
MGLOfflineStorage.shared.packs
To access these packs, you just need to iterate over the array or pass a specific index and retrieve whatever information you're interested in from the packs.
There is a good example of using this array to create a tableview of the completed offline packs on a device in the SDK's open source test app (NB: this example is written in Obj-C).
⚠️ Disclaimer: I currently work at Mabpox ⚠️
I was finally able to come to a solution. To observe the packs retrieval using Swift, you can use this code:
MGLOfflineStorage.shared.observe(\.packs, options: [.new, .old]){ object, change in
var offlinePacksArr : [MGLOfflinePack] = object.packs // Access to packs array here
}

Inter-App Data Migration (migrating data to new app version)

I currently have a Swift iOS app on Apple's App Store. I have many users and I would like to make a new version and help current users migrate to the new version. FYI: the new version is an Ionic app.
Data-wise, my app is using Core Data without any iCloud or sync support. It contains JSON data and also multiple images. So I'd need to bundle the current data and find a way of bringing it to the new ionic app version.
Basically my question is: Is there a way of writing in the app's documents directory and let the new version grab that file to import its data? Is there a way of letting both apps transmit data other than AirDrop or Custom URLs?
I don't want to upload the data remotely, I'd like to do this all locally on the device and also seamlessly so the user don't have to manually do anything.
Suggestions are welcome, thanks!
I would suggest using App Groups to get a shared container. I’m not familiar with Ionic, but this is quite straightforward in native Swift. It allows multiple apps or extensions to access a shared container of data, like the image below:
(Image from https://agostini.tech/2017/08/13/sharing-data-between-applications-and-extensions-using-app-groups/ )
This would require an update to the existing app to copy data to the shared container and then users would have to install the new app while the old one was still installed, because the shared container will be deleted when there are no installed apps using it.
It can be set up like this:
1: Enable App Groups in your project's Capabilities tab (for both apps).
2: Add a new app group and name it something like "group.appDomain.appName" or similar.
3: Now that the App Group is set up, it’s shared container can be used in several ways (User Defaults, NSCoding or Core Data).
For shared User Defaults:
let defaults = UserDefaults.init(suiteName: "group.appDomain.appName")
defaults.set("Example", forKey: "exampleKey")   
defaults.synchronize()
More info from Apple here.
For NSCoding:
let sharedContainerDirectory: URL = FileManager().containerURL(forSecurityApplicationGroupIdentifier: "group.appDomain.appName")!
let sharedArchiveURL: URL = sharedContainerDirectory.appendingPathComponent("whateverYouNeed")
NSKeyedArchiver.archiveRootObject(yourObject, toFile: sharedArchiveURL.path)
For Core Data:
You can set up the container as below. I have taken this code from this answer as I have not actually tried this with Core Data myself.
You use containerURL(forSecurityApplicationGroupIdentifier: "group.appDomain.appName")! to make this work in shared container.
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application.
This implementation creates and returns a container, having loaded the store for the application to it.
This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "xx")
let appName: String = "xx"
var persistentStoreDescriptions: NSPersistentStoreDescription
let storeUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.appDomain.appName")!.appendingPathComponent("xx.sqlite")
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
description.url = storeUrl
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.xxx.xx.container")!.appendingPathComponent("xx.sqlite"))]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
This answer provides a way to migrate the persistent store.
As I mentioned, I am not familiar with Ionic, so I’m not sure how working in that context might change this technique.
I hope this is helpful.
I would have just left a comment but I am unable to do so.
I was able to see that after loading a native iOS application then a Ionic project with the same bundle structure that the data within Library/Application Support/DisplayName.sqlite was still there and the data within the database still intact. (Note: this is deploying using Xcode not through the App Store)
You can see this using Xcode -> Window -> Devices and Simulators -> Devices tab -> Click on your app -> settings cog -> Download container -> after saving Show package contents
I was unable to use the Ionic SQLite native plugin to open the database for some reason. That is as far as I could get. I think it might have something to do with the space of the Application Support folder.
You can do the transition without using AirDrop or Custom Url. The idea is based on how ionic works. Much of the ionic functionality depends upon the plugins developed by community like working with hardware features.
Dealing with device specific features are done in native codes then JS wrapper classes are created for making a bridge between your code and native code.
I would suggest you to write native code which will access the data and files from CoreData and then use the cordova plugin tech to setup communication between the native code and the ionic code. here is a good post on Creating Custom Plugin for ionic and a sample github project

How to save to local storage using Flutter?

In Android, if I have the information I want to persist across sessions I know I can use SharedPreferences or create a SQLite database or even write a file to the device and read it in later.
Is there a way to save and restore data like this just using Flutter? Or would I need to write device-specific code for Android and iOS like in the services example?
There are a few options:
Read and write files: https://flutter.io/reading-writing-files/
SQLite via a Flutter plugin: https://github.com/tekartik/sqflite
SQLCipher via a Flutter plugin: https://github.com/drydart/flutter_sqlcipher
SharedPreferences via a Flutter plugin: https://github.com/flutter/plugins/tree/master/packages/shared_preferences
Localstore via a Flutter plugin: https://pub.dev/packages/localstore
If you are in a situation where you wanna save a small value that you wanna refer later. then you should store your data as key-value data using shared_preferences
Storing key-value data on disk
but if you want to store large data you should go with SQLITE
How to get Started with SQLITE in Flutter
however you can always use firebase database which is available offline
how to add firebase to your flutter project
Firebase for Flutter Codelab from google
Since we are talking about local storage you can always read and write files to the disk
Reading and Writing Files
Other solutions :
Simple Embedded Application Store database
A Flutter plugin to store data in secure storage
A late answer but I hope it will help anyone visiting here later too😁..
I will provide categories to save and their respective best methods...
Shared Preferences
Use this when storing simple values on storage e.g Color theme, app language, last scroll position(in reading apps).. these are simple settings that you would want to persist when the app restarts..
You could, however, use this to store large things(Lists, Maps, Images) but that would require serialization and deserialization.. To learn more on this deserialization and serialization go here.
Files
This helps a lot when you have data that is defined more by you for example log files, image files and maybe you want to export csv files.. I heard that this type of persistence can be washed by storage cleaners once disk runs out of space.. Am not sure as i have never seen it..
This also can store almost anything but with the help of serialization and deserialization..
Saving to a database
This is enormously helpful in data which is a bit complex. And I think this doesn't get washed up by disc cleaners as it is stored in AppData(for android)..
In this, your data is stored in an SQLite database. Its plugin is SQFLite.
Kinds of data that you might wanna put in here are like everything that can be represented by a database.
You can use shared preferences from flutter's official plugins.
https://github.com/flutter/plugins/tree/master/packages/shared_preferences
It uses Shared Preferences for Android, NSUserDefaults for iOS.
If you need to store just simple values like API token or login data (not passwords!), here is what I used:
import 'package:shared_preferences/shared_preferences.dart';
asyncFunc() async { // Async func to handle Futures easier; or use Future.then
SharedPreferences prefs = await SharedPreferences.getInstance();
}
...
// Set
prefs.setString('apiToken', token);
// Get
String token = prefs.getString('apiToken');
// Remove
prefs.remove('apiToken');
Don't forget to add shared_preferences dependency in your pubspec.yaml (preserve spacing format):
dependencies:
shared_preferences: any
You can use Localstorage
flutter pub add localstorage
1- Add dependency to pubspec.yaml (Change the version based on the last)
dependencies:
...
localstorage: ^4.0.0+1
2- Then run the following command
flutter packages get
3- import the localstorage :
import 'package:localstorage/localstorage.dart';
4- create an instance
class MainApp extends StatelessWidget {
final LocalStorage storage = new LocalStorage('localstorage_app');
...
}
Add item to lcoalstorage :
void addItemsToLocalStorage() {
storage.setItem('name', 'Abolfazl');
storage.setItem('family', 'Roshanzamir');
final info = json.encode({'name': 'Darush', 'family': 'Roshanzami'});
storage.setItem('info', info);
}
Get an item from lcoalstorage:
void getitemFromLocalStorage() {
final name = storage.getItem('name'); // Abolfazl
final family = storage.getItem('family'); // Roshanzamir
Map<String, dynamic> info = json.decode(storage.getItem('info'));
final info_name=info['name'];
final info_family=info['family'];
}
Delete an item from localstorage :
void removeItemFromLocalStorage() {
storage.deleteItem('name');
storage.deleteItem('family');
storage.deleteItem('info');
}
There are a few options:
Moor: Persistence library for Dart
https://pub.dev/packages/moor_flutter
Read and Write file
https://flutter.io/reading-writing-files/
Shared preferences plugin for flutter
https://pub.dev/packages/shared_preferences
SQlite for flutter
https://pub.dev/packages/sqflite
I was looking for the same, simple local storage but also with a reasonable level of security. The two solutions I've found that make the most sense are flutter_secure_storage (as mentioned by Raouf) for the small stuff, and hive for larger datasets.
I think If you are going to store large amount of data in local storage you can use sqflite library. It is very easy to setup and I have personally used for some test project and it works fine.
https://github.com/tekartik/sqflite
This a tutorial - https://proandroiddev.com/flutter-bookshelf-app-part-2-personal-notes-and-database-integration-a3b47a84c57
If you want to store data in cloud you can use firebase. It is solid service provide by google.
https://firebase.google.com/docs/flutter/setup
Hive (https://pub.dev/packages/hive) is very fast and flexible solution. But if you have experience with SQL; you can use SqfLite packages (https://pub.dev/packages/sqflite)