Sharing a big String between an app and its extension - string

I have a text file of 5MB and I need to send from my application to a content blocker extension. I tried a simple group sharing but it's not working, ehre is the code.
In my app:
listText = NSString(data: content, encoding: NSUTF8StringEncoding)! as String
print("\(list): \(listText.characters.count)") // It works
if let userDefaults = NSUserDefaults(suiteName: "group.AG.App") {
print("In the group") // It works
userDefaults.setObject(listText, forKey:"test")
userDefaults.synchronize()
}
In my extension:
if let userDefaults = NSUserDefaults(suiteName: "group.AG.App") {
// Things happen here
if let test = userDefaults.stringForKey("test") {
// Nothing happens here
}
}
How would you do to share a big amount of text between an app and its extension?

Since you load the string from a file and you already use App Groups, I suggest to save that file in the shared container and retrieve its content in the extension.
You can save file in the shared group in the same way you do for your app container. You only have to get the URL for the group root:
Swift
let groupRoot = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("com.group.Armand-Grillet")
Objective-C
NSURL *groupRoot = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"com.group.Armand-Grillet"];
You can't retrieve the string because you set a NSString and you try to retrieve an array, try to use stringForKey:

Related

The specified share already exists on Azure Storage File Shares

I am using "Azure Storage File Shares" to store some files from our website, but failed with error message "The specified share already exists".
I have change the file that being upload, but the error persist.
Here my code
public static void Test2Upload()
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
string connectionString = "DefaultEndpointsProtocol=https;AccountName=xxxxx;AccountKey=xxxxx;EndpointSuffix=core.windows.net";
string shareName = "myapp-dev";
string dirName = "files";
string fileName = "catto.jpg";
// Path to the local file to upload
string localFilePath = #"d:\temp\two.jpg";
// Get a reference to a share and then create it
ShareClient share = new ShareClient(connectionString, shareName);
share.Create();
// Get a reference to a directory and create it
ShareDirectoryClient directory = share.GetDirectoryClient(dirName);
directory.Create();
// Get a reference to a file and upload it
ShareFileClient file = directory.GetFileClient(fileName);
using (FileStream stream = File.OpenRead(localFilePath))
{
file.Create(stream.Length);
file.UploadRange(
new HttpRange(0, stream.Length),
stream);
}
}
Looks like I should not create ShareClient with same name several times.
Then how to check and use it?
The most important question is, why the file still not yet uploaded (even if I rename the ShareClient object)?
Looks like I should not create ShareClient with same name several
times. Then how to check and use it?
You can use ShareClient.CreateIfNotExists instead of ShareClient.Create method. Former will try to create a share but if a share already exists, then it won't be changed.
You can also use ShareClient.Exists to check if the share exists and then create it using ShareClient.Create if it does not exist. This is not recommended however as it might not work if multiple users are executing that code at the same time. Furthermore, you will be making 2 network calls - first to check the existence of share and then the second to create it.
The most important question is, why the file still not yet uploaded
(even if I rename the ShareClient object)?
Your code for uploading the file looks ok to me. Are you getting any error in that code?
We could use ShareClient.CreateIfNotExists when creating ShareClient object to avoid the problem. Like below
ShareClient share = new ShareClient(connectionString, shareName);
share.CreateIfNotExists();
You might found Similar problem on ShareDirectoryClient.
This part purpose is to create the folder structure.
The upload will fail if the destination folder is not exist.
Error will occur if we create a folder when it already exist.
So, use method ShareDirectoryClient.CreateIfNotExists, like below
ShareDirectoryClient directory = share.GetDirectoryClient(dirName);
directory.CreateIfNotExists();
Here my complete code
public static void TestUpload()
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
string connectionString = "DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xx;EndpointSuffix=core.windows.net";
string shareName = "myapp-dev";
string dirName = "myfiles";
string fileName = "catto.jpg";
string localFilePath = #"d:\temp\two.jpg";
// Get a reference to a share and then create it
ShareClient share = new ShareClient(connectionString, shareName);
share.CreateIfNotExists();
// Get a reference to a directory and create it
ShareDirectoryClient directory = share.GetDirectoryClient(dirName);
directory.CreateIfNotExists();
// Get a reference to a file and upload it
ShareFileClient file = directory.GetFileClient(fileName);
using (FileStream stream = File.OpenRead(localFilePath))
{
file.Create(stream.Length);
file.UploadRange(
new HttpRange(0, stream.Length),
stream);
}
}

SwiftUI: How to add CoreData record from Siri Intent

I am trying to create an Intent that saves a record to a CoreData database. The record will be created if I run the code from the main app, but not in the Intent.
Here is the code:
import Intents
import CoreData
import SwiftUI
let persistenceController = PersistenceController.shared
class IntentHandler: INExtension, DiaryIntentHandling
{
var moc = PersistenceController.shared.context
override func handler(for intent: INIntent) -> Any?
{
guard intent is DiaryIntent else
{
fatalError("Unknwonwn intent type: \(intent)")
}
return self
}
func handle(intent: DiaryIntent, completion: #escaping (DiaryIntentResponse) -> Void)
{
guard let message = message
else
{
completion(DiaryIntentResponse(code: .failure, userActivity: nil))
return
}
completion(DiaryIntentResponse.success(message: message))
let context = PersistenceController.shared.container.viewContext
let myRecord = MyRecord(context: context)
myRecord.timestamp = Date()
myRecord.message = message
do {
try context.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
func resolveMessage(for intent: DiaryIntent, with completion: #escaping (INStringResolutionResult) -> Void)
{
if let message = intent.message
{
completion(INStringResolutionResult.success(with: message))
}
else
{
completion(INStringResolutionResult.needsValue())
}
}
public func confirm(intent: DiaryIntent, completion: #escaping (DiaryIntentResponse) -> Void) {
completion(DiaryIntentResponse(code: .ready, userActivity: nil))
}
}
Do I need to share access to the CoreData database? How do I create the record?
App extensions work like separate apps, so you need to set up an app "group" to share data between them. It gives you a directory that's not part of your app's sandbox that your app and your app extensions can share. Using one requires some setup work:
Turn on app groups by adding the group entitlement. Apple has some documentation on this. I also have a somewhat old blog post that's still accurate as far as setting up the group.
Set up your persistent container use the group directory for Core Data. Normally it saves data in your app's sandbox, but you can tell it to use the app group directory. To do that,
Get a file URL for the directory using FileManager's function containerURL(forSecurityApplicationGroupIdentifier:). The argument is the same as your app group identifier.
Make sure this directory exists! It doesn't get created automatically. Use FileManager.default.fileExists(atPath:) to check if it exists, and if not, use FileManager.default.createDirectory(at:withIntermediateDirectories:attributes:) to create it.
Use a NSPersistentStoreDescription to tell your persistent container to use that URL for Core Data. That would be something like
let persistentContainer = NSPersistentContainer(name: containerName)
let persistentStoreDescription = NSPersistentStoreDescription(url: persistentStoreUrl)
persistentStoreDescription.type = NSSQLiteStoreType
persistentContainer.persistentStoreDescriptions = [ persistentStoreDescription ]
After the previous step, the persistent container won't be able to find any data that's currently in Core Data. So:
If your app has not already been released, delete it from your test devices and simulators and then rebuild. You'll get a new persistent store in the app group directory.
If your app has already been released, add code to copy the persistent store from the current location to the new location. Do this before loading the persistent store, and only do it if the copy in the app group doesn't already exist (so you don't re-copy old data). The best way to do that is with the migratePersistentStore(_:to:options:withType:) function from NSPersistentStoreCoordinator. Don't just copy your SQLite file over, because that won't include all the data.

File write permission in Azure Function App

I am using Azure Function App
I am using CSVHelper package to create file, But CSVHelper needs local file path first to Create/Write file.
using (var writer = new StreamWriter(filePath))
using (var csvData = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
// Write input in csv
csvData.WriteRecords(input);
}
What path can I use to create file in Azure Function App?
Since it looks like you're using a StreamWriter, you could also write to a MemoryStream instead of creating an actual file. This feels like a better route to take with Azure Functions.
If you're really set on creating an actual file, you can do so by using System.IO.Path.GetTempPath(), which will always return a valid path for any given system. Create your temporary file there, then continue with the process.
Please take into account that your Function might run multiple times on the same environment, so be sure to use a unique filename.
For future reference:
private static void ExportContentToCsv(ILogger log, IEnumerable<T> content)
{
var path = Path.Combine(Path.GetTempPath(), "content.csv");
log.LogInformation($"Writing csv file at {path}");
if (File.Exists(path))
{
log.LogInformation("Deleting existent resources...");
File.Delete(path);
}
using (var writer = new StreamWriter(path))
{
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(content);
}
}
}

Video saved in temp folder works in AVPlayer on simulator but not on real device

I am having a problem with AVPlayer, I'm using Parse SDK to store user files, and I want to fetch a movie file (.mp4) and display it using AVPlayer. There is a problem with using directly the Parse file url, so I'm trying a different approach:
// First, I load the file from the video url
// `name` is the file name fetched from Parse
URLSession.shared.dataTask(with: videoURL) { data, response, error in
DispatchQueue.main.async {
do {
// I will store locally the file to be read by AVPlayer afterwards
let filepath = FileManager.default.temporaryDirectory.appendingPathComponent(name)
try data?.write(to: filepath, options: .atomicWrite)
// I create an AVPlayerItem from the local url
let playerItem = AVPlayerItem(url: filepath as URL)
let player = AVPlayer(playerItem: playerItem)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.viewController?.present(playerViewController, animated: true) {
playerViewController.player?.play()
}
} catch {
print(error)
}
}
}.resume()
This works fine with the simulator, but I end up having no video playing when using a real device.
Any idea?
Thank you for your help

Sharing image via my app in xamarin.forms

I want to share an image. Sharing options should contain my app xyz. For example if I open an image and want to share it on instagram sharing options contains instagram,facebook,twitter,email etc. Like that my app should be in sharing options. How can I do that in xamarin.forms(both ios and android).
I think the app icon is created in a directory that is private to your app, so other apps wont be able to get at it.
You will need to save it out somewhere where the other apps can access it then share it from that location some thing like this:
public void Share (string title, string content)
{
if (string.IsNullOrEmpty (title) || string.IsNullOrEmpty (content))
return;
Bitmap b = BitmapFactory.DecodeResource(Resources,Resource.Drawable.icon_120);
var tempFilename = "test.png";
var sdCardPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
var filePath = System.IO.Path.Combine(sdCardPath, tempFilename);
using (var os = new FileStream(filePath, FileMode.Create))
{
b.Compress(Bitmap.CompressFormat.Png, 100, os);
}
b.Dispose ();
var imageUri = Android.Net.Uri.Parse ($"file://{sdCardPath}/{tempFilename}");
var sharingIntent = new Intent ();
sharingIntent.SetAction (Intent.ActionSend);
sharingIntent.SetType ("image/*");
sharingIntent.PutExtra (Intent.ExtraText, content);
sharingIntent.PutExtra (Intent.ExtraStream, imageUri);
sharingIntent.AddFlags (ActivityFlags.GrantReadUriPermission);
StartActivity (Intent.CreateChooser (sharingIntent, title));
}
Also add ReadExternalStorage and WriteExternalStorage permissions to your app.
Let me know if that works.

Resources