Výběr dokumentu v Xamarin.iOS
Výběr dokumentu umožňuje sdílení dokumentů mezi aplikacemi. Tyto dokumenty mohou být uložené v iCloudu nebo v adresáři jiné aplikace. Dokumenty se sdílí prostřednictvím sady rozšíření poskytovatele dokumentů, které uživatel nainstaloval na svém zařízení.
Kvůli obtížné synchronizaci dokumentů mezi aplikacemi a cloudem přináší určitá složitost.
Požadavky
K dokončení kroků uvedených v tomto článku je potřeba provést následující:
- Xcode 7 a iOS 8 nebo novější – rozhraní API Xcode 7 a iOS 8 společnosti Apple nebo novější musí být nainstalovaná a nakonfigurovaná na počítači vývojáře.
- Visual Studio nebo Visual Studio pro Mac – musí být nainstalovaná nejnovější Visual Studio pro Mac aplikace.
- Zařízení s iOSem – zařízení s iOSem 8 nebo vyšším.
Změny iCloudu
Při implementaci nových funkcí výběru dokumentů byly ve službě iCloud společnosti Apple provedeny následující změny:
- Démon iCloudu byl zcela přepsán pomocí CloudKitu.
- Stávající funkce iCloudu se přejmenují na iCloud Drive.
- Do iCloudu Windows byla přidána podpora operačního systému Microsoft Windows.
- Do aplikace Finder se přidala složka Mac OS iCloud.
- Zařízení s iOSem mají přístup k obsahu Mac OS iCloudu.
Důležité
Apple poskytuje nástroje, které vývojářům pomůžou správně zvládnout požadavky Evropské unie Obecné nařízení o ochraně osobních údajů (GDPR).
Co je dokument?
Když odkazujete na dokument v iCloudu, jedná se o jedinou samostatnou entitu, kterou by měl uživatel vnímat jako takovou. Uživatel může chtít upravit dokument nebo ho sdílet s ostatními uživateli (například pomocí e-mailu).
Existuje několik typů souborů, které uživatel okamžitě rozpozná jako dokumenty, jako jsou například soubory Pages, Keynote nebo Numbers. ICloud se ale na tento koncept nemezuje. Například stav hry (například shoda s Match) se může považovat za dokument a uložit do iCloudu. Tento soubor se může předát mezi zařízeními uživatele a umožnit mu pustit se do hry, ve které na jiném zařízení opustili.
Práce s dokumenty
Než se začnete věnovat kódu potřebnému k použití nástroje pro výběr dokumentů s Xamarinem, tento článek se bude věnovat osvědčeným postupům pro práci s dokumenty iCloudu a několika úpravami stávajících rozhraní API, které jsou nutné pro podporu výběru dokumentů.
Použití koordinace souborů
Vzhledem k tomu, že soubor lze upravit z několika různých umístění, je nutné použít koordinaci, aby se zabránilo ztrátě dat.
Podívejme se na výše uvedený obrázek:
- Zařízení s iOSem, které používá koordinaci souborů, vytvoří nový dokument a uloží ho do složky iCloudu.
- iCloud uloží upravený soubor do cloudu pro distribuci do každého zařízení.
- Připojený Mac vidí upravený soubor ve složce iCloudu a pomocí koordinace souborů zkopíruje změny do souboru.
- Zařízení, které koordinaci souborů používá, provede změnu souboru a uloží ho do složky iCloudu. Tyto změny se okamžitě replikují do ostatních zařízení.
Předpokládejme, že původní zařízení s iOSem nebo Mac upravoval soubor. Teď se jejich změny ztratí a přepíšou verzí souboru ze zařízení bez vrátek. Abyste zabránili ztrátě dat, koordinace souborů je při práci s cloudovými dokumenty nutné.
Použití objektu UIDocument
UIDocument usnadňuje práci (nebo v systému macOS) tím, že vývojářům dělá všechny NSDocument náročné věci. Poskytuje integrovanou koordinaci souborů s frontami na pozadí, které brání blokování uživatelského rozhraní aplikace.
UIDocument zpřístupňuje několik rozhraní API vysoké úrovně, která usnadňují vývoj aplikací Xamarin pro všechny účely, které vývojář vyžaduje.
Následující kód vytvoří podtřídu pro implementaci obecného textového dokumentu, který lze použít k ukládání UIDocument a načítání textu z iCloudu:
using System;
using Foundation;
using UIKit;
namespace DocPicker
{
public class GenericTextDocument : UIDocument
{
#region Private Variable Storage
private NSString _dataModel;
#endregion
#region Computed Properties
public string Contents {
get { return _dataModel.ToString (); }
set { _dataModel = new NSString(value); }
}
#endregion
#region Constructors
public GenericTextDocument (NSUrl url) : base (url)
{
// Set the default document text
this.Contents = "";
}
public GenericTextDocument (NSUrl url, string contents) : base (url)
{
// Set the default document text
this.Contents = contents;
}
#endregion
#region Override Methods
public override bool LoadFromContents (NSObject contents, string typeName, out NSError outError)
{
// Clear the error state
outError = null;
// Were any contents passed to the document?
if (contents != null) {
_dataModel = NSString.FromData( (NSData)contents, NSStringEncoding.UTF8 );
}
// Inform caller that the document has been modified
RaiseDocumentModified (this);
// Return success
return true;
}
public override NSObject ContentsForType (string typeName, out NSError outError)
{
// Clear the error state
outError = null;
// Convert the contents to a NSData object and return it
NSData docData = _dataModel.Encode(NSStringEncoding.UTF8);
return docData;
}
#endregion
#region Events
public delegate void DocumentModifiedDelegate(GenericTextDocument document);
public event DocumentModifiedDelegate DocumentModified;
internal void RaiseDocumentModified(GenericTextDocument document) {
// Inform caller
if (this.DocumentModified != null) {
this.DocumentModified (document);
}
}
#endregion
}
}
Výše uvedená třída se bude používat v tomto článku při práci s výběrem dokumentů a externími dokumenty GenericTextDocument v aplikaci Xamarin.iOS 8.
Asynchronní koordinace souborů
iOS 8 poskytuje několik nových funkcí asynchronní koordinace souborů prostřednictvím nových rozhraní API pro koordinaci souborů. Před iOSem 8 byla všechna existující rozhraní API pro koordinaci souborů zcela synchronní. To znamená, že vývojář zodpovídá za implementaci vlastního řízení front na pozadí, aby zabránil koordinaci souborů v blokování uživatelského rozhraní aplikace.
Nová třída obsahuje adresu URL odkazující na soubor a několik možností pro řízení NSFileAccessIntent požadovaného typu koordinace. Následující kód ukazuje přesunutí souboru z jednoho umístění do jiného pomocí záměrů:
// Get source options
var srcURL = NSUrl.FromFilename ("FromFile.txt");
var srcIntent = NSFileAccessIntent.CreateReadingIntent (srcURL, NSFileCoordinatorReadingOptions.ForUploading);
// Get destination options
var dstURL = NSUrl.FromFilename ("ToFile.txt");
var dstIntent = NSFileAccessIntent.CreateReadingIntent (dstURL, NSFileCoordinatorReadingOptions.ForUploading);
// Create an array
var intents = new NSFileAccessIntent[] {
srcIntent,
dstIntent
};
// Initialize a file coordination with intents
var queue = new NSOperationQueue ();
var fileCoordinator = new NSFileCoordinator ();
fileCoordinator.CoordinateAccess (intents, queue, (err) => {
// Was there an error?
if (err!=null) {
Console.WriteLine("Error: {0}",err.LocalizedDescription);
}
});
Zjišťování a výpis dokumentů
Ke zjišťování a zobrazení seznamu dokumentů můžete použít stávající NSMetadataQuery rozhraní API. Tato část se bude vztahovat na nové funkce NSMetadataQuery přidané do , které práci s dokumenty ještě usnadňují než dřív.
Existující chování
Před iOSem 8 se pomalé vyzvednutí změn místních souborů, NSMetadataQuery například: odstraní, vytvoří a přejmenuje.
Ve výše uvedeném diagramu:
- Pro soubory, které již existují v kontejneru aplikace, jsou předem vytvořené a zařazované existující záznamy, aby byly pro aplikaci
NSMetadataQueryNSMetadataokamžitě dostupné. - Aplikace vytvoří nový soubor v kontejneru aplikace.
- Před zobrazením změny kontejneru aplikace a vytvořením požadovaného záznamu je
NSMetadataQueryNSMetadataprodleva.
Kvůli zpoždění při vytváření záznamu musela mít aplikace otevřené dva zdroje dat: jeden pro změny místních souborů a jeden pro NSMetadata cloudové změny.
Šití
V iOSu 8 se přímé použití usnadňuje s NSMetadataQuery novou funkcí s názvem Spojování:
Použití spojování ve výše uvedeném diagramu:
- Stejně jako předtím má soubor, který už v kontejneru aplikace existuje, existující záznamy předem vytvořené
NSMetadataQueryNSMetadataa zařazované. - Aplikace vytvoří nový soubor v kontejneru aplikace pomocí koordinace souborů.
- Hook v kontejneru aplikace uvidí úpravy a volání pro
NSMetadataQueryvytvoření požadovanéhoNSMetadatazáznamu. - Záznam
NSMetadatase vytvoří přímo po souboru a je k dispozici pro aplikaci.
Pomocí spojování aplikace už nemusí otevírat zdroj dat pro monitorování změn místních a cloudových souborů. Aplikace se teď může spolehnout NSMetadataQuery přímo na .
Důležité
Spojování funguje pouze v případě, že aplikace používá koordinaci souborů, jak je uvedeno v části výše. Pokud se koordinace souborů používá, rozhraní API ve výchozím nastavení používají stávající chování před iOSem 8.
Nové funkce metadat iOS 8
V iOSu 8 byly do NSMetadataQuery systému přidány následující nové funkce:
NSMetatadataQueryteď může zobrazit seznam jiných než místních dokumentů uložených v cloudu.- Přidali jsme nová rozhraní API pro přístup k informacím o metadatech v cloudových dokumentech.
- K dispozici je nové rozhraní API, které bude přistupovat k atributům souborů, které mohou nebo nemusí mít
NSUrl_PromisedItemsmístně k dispozici jejich obsah. - Pomocí metody můžete získat informace o daném souboru nebo použít metodu k získání informací o více
GetPromisedItemResourceValueGetPromisedItemResourceValuesnež jednom souboru najednou.
Pro práci s metadaty byly přidány dva nové příznaky koordinace souborů:
NSFileCoordinatorReadImmediatelyAvailableMetadataOnlyNSFileCoordinatorWriteContentIndependentMetadataOnly
S výše uvedenými příznaky nemusí být obsah souboru Dokumentu k dispozici místně, aby se použily.
Následující segment kódu ukazuje, jak použít k dotazování na existenci konkrétního souboru a sestavení souboru, pokud NSMetadataQuery neexistuje:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Foundation;
using UIKit;
using ObjCRuntime;
using System.IO;
#region Static Properties
public const string TestFilename = "test.txt";
#endregion
#region Computed Properties
public bool HasiCloud { get; set; }
public bool CheckingForiCloud { get; set; }
public NSUrl iCloudUrl { get; set; }
public GenericTextDocument Document { get; set; }
public NSMetadataQuery Query { get; set; }
#endregion
#region Private Methods
private void FindDocument () {
Console.WriteLine ("Finding Document...");
// Create a new query and set it's scope
Query = new NSMetadataQuery();
Query.SearchScopes = new NSObject [] {
NSMetadataQuery.UbiquitousDocumentsScope,
NSMetadataQuery.UbiquitousDataScope,
NSMetadataQuery.AccessibleUbiquitousExternalDocumentsScope
};
// Build a predicate to locate the file by name and attach it to the query
var pred = NSPredicate.FromFormat ("%K == %@"
, new NSObject[] {
NSMetadataQuery.ItemFSNameKey
, new NSString(TestFilename)});
Query.Predicate = pred;
// Register a notification for when the query returns
NSNotificationCenter.DefaultCenter.AddObserver (this,
new Selector("queryDidFinishGathering:"), NSMetadataQuery.DidFinishGatheringNotification,
Query);
// Start looking for the file
Query.StartQuery ();
Console.WriteLine ("Querying: {0}", Query.IsGathering);
}
[Export("queryDidFinishGathering:")]
public void DidFinishGathering (NSNotification notification) {
Console.WriteLine ("Finish Gathering Documents.");
// Access the query and stop it from running
var query = (NSMetadataQuery)notification.Object;
query.DisableUpdates();
query.StopQuery();
// Release the notification
NSNotificationCenter.DefaultCenter.RemoveObserver (this
, NSMetadataQuery.DidFinishGatheringNotification
, query);
// Load the document that the query returned
LoadDocument(query);
}
private void LoadDocument (NSMetadataQuery query) {
Console.WriteLine ("Loading Document...");
// Take action based on the returned record count
switch (query.ResultCount) {
case 0:
// Create a new document
CreateNewDocument ();
break;
case 1:
// Gain access to the url and create a new document from
// that instance
NSMetadataItem item = (NSMetadataItem)query.ResultAtIndex (0);
var url = (NSUrl)item.ValueForAttribute (NSMetadataQuery.ItemURLKey);
// Load the document
OpenDocument (url);
break;
default:
// There has been an issue
Console.WriteLine ("Issue: More than one document found...");
break;
}
}
#endregion
#region Public Methods
public void OpenDocument(NSUrl url) {
Console.WriteLine ("Attempting to open: {0}", url);
Document = new GenericTextDocument (url);
// Open the document
Document.Open ( (success) => {
if (success) {
Console.WriteLine ("Document Opened");
} else
Console.WriteLine ("Failed to Open Document");
});
// Inform caller
RaiseDocumentLoaded (Document);
}
public void CreateNewDocument() {
// Create path to new file
// var docsFolder = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
var docsFolder = Path.Combine(iCloudUrl.Path, "Documents");
var docPath = Path.Combine (docsFolder, TestFilename);
var ubiq = new NSUrl (docPath, false);
// Create new document at path
Console.WriteLine ("Creating Document at:" + ubiq.AbsoluteString);
Document = new GenericTextDocument (ubiq);
// Set the default value
Document.Contents = "(default value)";
// Save document to path
Document.Save (Document.FileUrl, UIDocumentSaveOperation.ForCreating, (saveSuccess) => {
Console.WriteLine ("Save completion:" + saveSuccess);
if (saveSuccess) {
Console.WriteLine ("Document Saved");
} else {
Console.WriteLine ("Unable to Save Document");
}
});
// Inform caller
RaiseDocumentLoaded (Document);
}
public bool SaveDocument() {
bool successful = false;
// Save document to path
Document.Save (Document.FileUrl, UIDocumentSaveOperation.ForOverwriting, (saveSuccess) => {
Console.WriteLine ("Save completion: " + saveSuccess);
if (saveSuccess) {
Console.WriteLine ("Document Saved");
successful = true;
} else {
Console.WriteLine ("Unable to Save Document");
successful=false;
}
});
// Return results
return successful;
}
#endregion
#region Events
public delegate void DocumentLoadedDelegate(GenericTextDocument document);
public event DocumentLoadedDelegate DocumentLoaded;
internal void RaiseDocumentLoaded(GenericTextDocument document) {
// Inform caller
if (this.DocumentLoaded != null) {
this.DocumentLoaded (document);
}
}
#endregion
Miniatury dokumentů
Apple má pocit, že nejlepší uživatelské prostředí při výpisu dokumentů pro aplikaci je použití náhledů. To dává koncovým uživatelům kontext, aby mohli rychle identifikovat dokument, se který chtějí pracovat.
Před iOSem 8 vyžadovalo zobrazení náhledů dokumentů vlastní implementaci. Novinka v iOSu 8 jsou atributy systému souborů, které vývojářům umožňují rychle pracovat s miniaturami dokumentů.
Načítání miniatur dokumentů
Voláním GetPromisedItemResourceValue metod nebo GetPromisedItemResourceValues se vrátí rozhraní NSUrl_PromisedItems API NSUrlThumbnailDictionary . Jediný klíč aktuálně v tomto slovníku je a NSThumbnial1024X1024SizeKey jeho odpovídající UIImage .
Ukládání miniatur dokumentů
Nejjednodušší způsob, jak uložit miniaturu, je použít UIDocument . Voláním metody a nastavením miniatury se automaticky uloží, když je GetFileAttributesToWriteUIDocument soubor Document. Démon iCloudu tuto změnu uvidí a rozšíří ji do iCloudu. Na Mac OS X modul plug-in Rychlý vzhled automaticky generuje miniatury pro vývojáře.
Se základy práce s dokumenty založenými na iCloudu a se změnami stávajícího rozhraní API jsme připraveni implementovat kontroler zobrazení pro výběr dokumentů v mobilní aplikaci Xamarin iOS 8.
Povolení iCloudu v Xamarinu
Než bude možné výběr dokumentů použít v aplikaci Xamarin.iOS, je potřeba povolit podporu iCloudu ve vaší aplikaci i přes Apple.
Následující kroky popisují proces zřizování pro iCloud.
- Vytvořte kontejner iCloudu.
- Vytvořte ID aplikace, které obsahuje id iCloudu App Service.
- Vytvořte zřizovací profil, který obsahuje toto ID aplikace.
Průvodce Práce s funkcemi vás provede prvními dvěma kroky. Pokud chcete vytvořit zřizovací profil, postupujte podle pokynů v průvodci zřizovacím profilem.
Následující kroky vás pro názorný postup konfigurace aplikace pro iCloud:
Postupujte následovně:
Otevřete projekt v Visual Studio pro Mac nebo Visual Studio.
V Průzkumník řešeníklikněte pravým tlačítkem na projekt a vyberte Možnosti.
V dialogovém okně Možnosti vyberte Aplikace pro iOSa ujistěte se, že identifikátor sady odpovídá identifikátoru definovanému v ID aplikace vytvořeném výše pro aplikaci.
Vyberte iOS Bundle Signing (Podepisovánísady prostředků iOS), vyberte Vývojářská identita a Zřizovací profil vytvořený výše.
Kliknutím na tlačítko OK uložte změny a zavřete dialogové okno.
Klikněte pravým tlačítkem
Entitlements.plistna vEntitlements.plista otevřete ho v editoru.Důležité
V Visual Studio možná budete muset otevřít editor nároků tak, že na něj kliknete pravým tlačítkem, vyberete Otevřít s... a vyberete Editor seznamu vlastností.
Zaškrtněte políčko Povolit iCloud,Dokumenty na iCloudu,Úložiště s klíčovou hodnotou a CloudKit.
Ujistěte se, že kontejner pro aplikaci existuje (jak bylo vytvořeno výše). Příklad:
iCloud.com.your-company.AppNameUložte změny souboru.
Další informace o nárocích najdete v příručce Práce s nároky.
S výše uvedenými nastaveními teď může aplikace používat cloudové dokumenty a nový kontroler zobrazení pro výběr dokumentů.
Běžný instalační kód
Než začnete s kontroleru zobrazení pro výběr dokumentů, je potřeba nějaký standardní instalační kód. Začněte úpravou souboru aplikace, aby AppDelegate.cs vypadal takto:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Foundation;
using UIKit;
using ObjCRuntime;
using System.IO;
namespace DocPicker
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
#region Static Properties
public const string TestFilename = "test.txt";
#endregion
#region Computed Properties
public override UIWindow Window { get; set; }
public bool HasiCloud { get; set; }
public bool CheckingForiCloud { get; set; }
public NSUrl iCloudUrl { get; set; }
public GenericTextDocument Document { get; set; }
public NSMetadataQuery Query { get; set; }
public NSData Bookmark { get; set; }
#endregion
#region Private Methods
private void FindDocument () {
Console.WriteLine ("Finding Document...");
// Create a new query and set it's scope
Query = new NSMetadataQuery();
Query.SearchScopes = new NSObject [] {
NSMetadataQuery.UbiquitousDocumentsScope,
NSMetadataQuery.UbiquitousDataScope,
NSMetadataQuery.AccessibleUbiquitousExternalDocumentsScope
};
// Build a predicate to locate the file by name and attach it to the query
var pred = NSPredicate.FromFormat ("%K == %@",
new NSObject[] {NSMetadataQuery.ItemFSNameKey
, new NSString(TestFilename)});
Query.Predicate = pred;
// Register a notification for when the query returns
NSNotificationCenter.DefaultCenter.AddObserver (this
, new Selector("queryDidFinishGathering:")
, NSMetadataQuery.DidFinishGatheringNotification
, Query);
// Start looking for the file
Query.StartQuery ();
Console.WriteLine ("Querying: {0}", Query.IsGathering);
}
[Export("queryDidFinishGathering:")]
public void DidFinishGathering (NSNotification notification) {
Console.WriteLine ("Finish Gathering Documents.");
// Access the query and stop it from running
var query = (NSMetadataQuery)notification.Object;
query.DisableUpdates();
query.StopQuery();
// Release the notification
NSNotificationCenter.DefaultCenter.RemoveObserver (this
, NSMetadataQuery.DidFinishGatheringNotification
, query);
// Load the document that the query returned
LoadDocument(query);
}
private void LoadDocument (NSMetadataQuery query) {
Console.WriteLine ("Loading Document...");
// Take action based on the returned record count
switch (query.ResultCount) {
case 0:
// Create a new document
CreateNewDocument ();
break;
case 1:
// Gain access to the url and create a new document from
// that instance
NSMetadataItem item = (NSMetadataItem)query.ResultAtIndex (0);
var url = (NSUrl)item.ValueForAttribute (NSMetadataQuery.ItemURLKey);
// Load the document
OpenDocument (url);
break;
default:
// There has been an issue
Console.WriteLine ("Issue: More than one document found...");
break;
}
}
#endregion
#region Public Methods
public void OpenDocument(NSUrl url) {
Console.WriteLine ("Attempting to open: {0}", url);
Document = new GenericTextDocument (url);
// Open the document
Document.Open ( (success) => {
if (success) {
Console.WriteLine ("Document Opened");
} else
Console.WriteLine ("Failed to Open Document");
});
// Inform caller
RaiseDocumentLoaded (Document);
}
public void CreateNewDocument() {
// Create path to new file
// var docsFolder = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
var docsFolder = Path.Combine(iCloudUrl.Path, "Documents");
var docPath = Path.Combine (docsFolder, TestFilename);
var ubiq = new NSUrl (docPath, false);
// Create new document at path
Console.WriteLine ("Creating Document at:" + ubiq.AbsoluteString);
Document = new GenericTextDocument (ubiq);
// Set the default value
Document.Contents = "(default value)";
// Save document to path
Document.Save (Document.FileUrl, UIDocumentSaveOperation.ForCreating, (saveSuccess) => {
Console.WriteLine ("Save completion:" + saveSuccess);
if (saveSuccess) {
Console.WriteLine ("Document Saved");
} else {
Console.WriteLine ("Unable to Save Document");
}
});
// Inform caller
RaiseDocumentLoaded (Document);
}
/// <summary>
/// Saves the document.
/// </summary>
/// <returns><c>true</c>, if document was saved, <c>false</c> otherwise.</returns>
public bool SaveDocument() {
bool successful = false;
// Save document to path
Document.Save (Document.FileUrl, UIDocumentSaveOperation.ForOverwriting, (saveSuccess) => {
Console.WriteLine ("Save completion: " + saveSuccess);
if (saveSuccess) {
Console.WriteLine ("Document Saved");
successful = true;
} else {
Console.WriteLine ("Unable to Save Document");
successful=false;
}
});
// Return results
return successful;
}
#endregion
#region Override Methods
public override void FinishedLaunching (UIApplication application)
{
// Start a new thread to check and see if the user has iCloud
// enabled.
new Thread(new ThreadStart(() => {
// Inform caller that we are checking for iCloud
CheckingForiCloud = true;
// Checks to see if the user of this device has iCloud
// enabled
var uburl = NSFileManager.DefaultManager.GetUrlForUbiquityContainer(null);
// Connected to iCloud?
if (uburl == null)
{
// No, inform caller
HasiCloud = false;
iCloudUrl =null;
Console.WriteLine("Unable to connect to iCloud");
InvokeOnMainThread(()=>{
var okAlertController = UIAlertController.Create ("iCloud Not Available", "Developer, please check your Entitlements.plist, Bundle ID and Provisioning Profiles.", UIAlertControllerStyle.Alert);
okAlertController.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, null));
Window.RootViewController.PresentViewController (okAlertController, true, null);
});
}
else
{
// Yes, inform caller and save location the Application Container
HasiCloud = true;
iCloudUrl = uburl;
Console.WriteLine("Connected to iCloud");
// If we have made the connection with iCloud, start looking for documents
InvokeOnMainThread(()=>{
// Search for the default document
FindDocument ();
});
}
// Inform caller that we are no longer looking for iCloud
CheckingForiCloud = false;
})).Start();
}
// This method is invoked when the application is about to move from active to inactive state.
// OpenGL applications should use this method to pause.
public override void OnResignActivation (UIApplication application)
{
}
// This method should be used to release shared resources and it should store the application state.
// If your application supports background execution this method is called instead of WillTerminate
// when the user quits.
public override void DidEnterBackground (UIApplication application)
{
// Trap all errors
try {
// Values to include in the bookmark packet
var resources = new string[] {
NSUrl.FileSecurityKey,
NSUrl.ContentModificationDateKey,
NSUrl.FileResourceIdentifierKey,
NSUrl.FileResourceTypeKey,
NSUrl.LocalizedNameKey
};
// Create the bookmark
NSError err;
Bookmark = Document.FileUrl.CreateBookmarkData (NSUrlBookmarkCreationOptions.WithSecurityScope, resources, iCloudUrl, out err);
// Was there an error?
if (err != null) {
// Yes, report it
Console.WriteLine ("Error Creating Bookmark: {0}", err.LocalizedDescription);
}
}
catch (Exception e) {
// Report error
Console.WriteLine ("Error: {0}", e.Message);
}
}
// This method is called as part of the transition from background to active state.
public override void WillEnterForeground (UIApplication application)
{
// Is there any bookmark data?
if (Bookmark != null) {
// Trap all errors
try {
// Yes, attempt to restore it
bool isBookmarkStale;
NSError err;
var srcUrl = new NSUrl (Bookmark, NSUrlBookmarkResolutionOptions.WithSecurityScope, iCloudUrl, out isBookmarkStale, out err);
// Was there an error?
if (err != null) {
// Yes, report it
Console.WriteLine ("Error Loading Bookmark: {0}", err.LocalizedDescription);
} else {
// Load document from bookmark
OpenDocument (srcUrl);
}
}
catch (Exception e) {
// Report error
Console.WriteLine ("Error: {0}", e.Message);
}
}
}
// This method is called when the application is about to terminate. Save data, if needed.
public override void WillTerminate (UIApplication application)
{
}
#endregion
#region Events
public delegate void DocumentLoadedDelegate(GenericTextDocument document);
public event DocumentLoadedDelegate DocumentLoaded;
internal void RaiseDocumentLoaded(GenericTextDocument document) {
// Inform caller
if (this.DocumentLoaded != null) {
this.DocumentLoaded (document);
}
}
#endregion
}
}
Důležité
Výše uvedený kód obsahuje kód z výše uvedené části Zjišťování a výpis dokumentů. Je zde uveden jako celý, jak by se objevil ve skutečné aplikaci. Pro zjednodušení tento příklad funguje pouze s jedním, pevným souborem ( test.txt ).
Výše uvedený kód zpřístupňuje několik zástupců pro iCloud Drive, aby se s nimi ve zbytku aplikace snadněji pracovalo.
Dále přidejte následující kód do libovolného kontejneru zobrazení nebo zobrazení, který bude používat výběr dokumentu nebo pracovat s cloudovými dokumenty:
using CloudKit;
...
#region Computed Properties
/// <summary>
/// Returns the delegate of the current running application
/// </summary>
/// <value>The this app.</value>
public AppDelegate ThisApp {
get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
}
#endregion
Tím se přidá zástupce pro přístup k a AppDelegate přístup k zástupcům iCloudu vytvořeným výše.
S tímto kódem se podíváme na implementaci kontroleru zobrazení pro výběr dokumentu v aplikaci Xamarin iOS 8.
Použití kontroleru zobrazení pro výběr dokumentu
Před iOSem 8 bylo velmi obtížné přistupovat k dokumentům z jiné aplikace, protože v aplikaci nebylo způsob, jak z aplikace zjišťovat dokumenty mimo aplikaci.
Existující chování
Pojďme se podívat na přístup k externímu dokumentu před iOSem 8:
- Uživatel musí nejprve otevřít aplikaci, která původně vytvořila dokument.
- Vybere se Dokument a
UIDocumentInteractionControllerpoužije se k odeslání dokumentu do nové aplikace. - Nakonec se do kontejneru nové aplikace umístí kopie původního dokumentu.
Odtud je dokument k dispozici pro druhou aplikaci k otevření a úpravě.
Zjišťování dokumentů mimo kontejner aplikace
V iOSu 8 má aplikace snadný přístup k dokumentům mimo svůj vlastní kontejner aplikací:
Pomocí nového nástroje pro výběr dokumentů na iCloudu ( ) může aplikace pro iOS přímo zjišťovat a přistupovat UIDocumentPickerViewController mimo svůj kontejner aplikace. Poskytuje mechanismus, který uživateli umožňuje udělit přístup k zjištěných dokumentům a upravovat je UIDocumentPickerViewController prostřednictvím oprávnění.
Aplikace musí vyjádřit výslovný souhlas, aby se její dokumenty ve výběru dokumentů na iCloudu objevily a aby je ostatní aplikace mohl zjišťovat a pracovat s nimi. Pokud chcete, aby aplikace Xamarin iOS 8 sdílela svůj kontejner aplikace, upravte ho ve standardním textovém editoru a přidejte následující dva řádky do dolní části slovníku Info.plist (mezi <dict>...</dict> značky):
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
Poskytuje UIDocumentPickerViewController skvělé nové uživatelské rozhraní, které umožňuje uživateli vybrat dokumenty. Pokud chcete zobrazit kontroler zobrazení pro výběr dokumentu v aplikaci Xamarin iOS 8, proveďte následující kroky:
using MobileCoreServices;
...
// Allow the Document picker to select a range of document types
var allowedUTIs = new string[] {
UTType.UTF8PlainText,
UTType.PlainText,
UTType.RTF,
UTType.PNG,
UTType.Text,
UTType.PDF,
UTType.Image
};
// Display the picker
//var picker = new UIDocumentPickerViewController (allowedUTIs, UIDocumentPickerMode.Open);
var pickerMenu = new UIDocumentMenuViewController(allowedUTIs, UIDocumentPickerMode.Open);
pickerMenu.DidPickDocumentPicker += (sender, args) => {
// Wireup Document Picker
args.DocumentPicker.DidPickDocument += (sndr, pArgs) => {
// IMPORTANT! You must lock the security scope before you can
// access this file
var securityEnabled = pArgs.Url.StartAccessingSecurityScopedResource();
// Open the document
ThisApp.OpenDocument(pArgs.Url);
// IMPORTANT! You must release the security lock established
// above.
pArgs.Url.StopAccessingSecurityScopedResource();
};
// Display the document picker
PresentViewController(args.DocumentPicker,true,null);
};
pickerMenu.ModalPresentationStyle = UIModalPresentationStyle.Popover;
PresentViewController(pickerMenu,true,null);
UIPopoverPresentationController presentationPopover = pickerMenu.PopoverPresentationController;
if (presentationPopover!=null) {
presentationPopover.SourceView = this.View;
presentationPopover.PermittedArrowDirections = UIPopoverArrowDirection.Down;
presentationPopover.SourceRect = ((UIButton)s).Frame;
}
Důležité
Než bude možné získat přístup k externímu dokumentu, musí vývojář StartAccessingSecurityScopedResourceNSUrl volat metodu . Po načtení dokumentu musí být volána metoda , která uvolní StopAccessingSecurityScopedResource zámek zabezpečení.
Vzorový výstup
Tady je příklad, jak by výše uvedený kód při spuštění na zařízení s iPhone dokumentů:
Uživatel spustí aplikaci a zobrazí se hlavní rozhraní:
Uživatel klepne na tlačítko Akce v horní části obrazovky a zobrazí se dotaz, jestli má v seznamu dostupných poskytovatelů vybrat poskytovatele dokumentů:
Pro vybraného poskytovatele dokumentů se zobrazí kontroler zobrazení pro výběr dokumentu:
Uživatel klepnutím na složku dokumentu zobrazí její obsah:
Uživatel vybere dokument a výběr dokumentu se zavře.
Hlavní rozhraní se znovu zobrazí, dokument se načte z externího kontejneru a zobrazí se jeho obsah.
Skutečné zobrazení kontroleru zobrazení pro výběr dokumentu závisí na poskytovatelích dokumentů, které uživatel na zařízení nainstaloval a jaký režim výběru dokumentů byl implementovaný. Výše uvedený příklad používá otevřený režim, ostatní typy režimu budou podrobněji popsány níže.
Správa externích dokumentů
Jak je uvedeno výše, před iOSem 8 měla aplikace přístup jenom k dokumentům, které byly součástí jejího kontejneru aplikací. V iOSu 8 má aplikace přístup k dokumentům z externích zdrojů:
Když uživatel vybere dokument z externího zdroje, do kontejneru aplikace se zapisuje referenční dokument, který odkazuje na původní dokument.
Pro pomoc s přidáním této nové možnosti do existujících aplikací bylo do rozhraní API přidáno několik nových NSMetadataQuery funkcí. Aplikace obvykle používá obor všudypřítomných dokumentů k zobrazení seznamu dokumentů, které jsou v kontejneru aplikace. Při použití tohoto oboru se budou dál zobrazovat pouze dokumenty v rámci kontejneru aplikace.
Použití nového oboru všudypřítomných externích dokumentů vrátí dokumenty, které se nachází mimo kontejner aplikace, a vrátí pro ně metadata. NSMetadataItemUrlKeyBude odkazovat na adresu URL, kde se dokument skutečně nachází.
Někdy aplikace nechce pracovat s dokumenty, na které odkaz odkazuje. Místo toho chce aplikace pracovat přímo s referenčním dokumentem. Aplikace může například chtít zobrazit dokument ve složce aplikace v uživatelském rozhraní nebo umožnit uživateli přesunout odkazy ve složce.
V iOSu 8 byl poskytnut nový dokument pro přímý přístup NSMetadataItemUrlInLocalContainerKey k referenčnímu dokumentu. Tento klíč odkazuje na skutečný odkaz na externí dokument v kontejneru aplikace.
Slouží NSMetadataUbiquitousItemIsExternalDocumentKey k otestování, jestli je dokument externí ke kontejneru aplikace. slouží NSMetadataUbiquitousItemContainerDisplayNameKey k přístupu k názvu kontejneru, který se nachází v původní kopii externího dokumentu.
Proč jsou vyžadovány odkazy na dokument
Hlavním důvodem, proč iOS 8 používá odkazy pro přístup k externím dokumentům, je zabezpečení. Žádná aplikace nemá přístup k žádnému kontejneru jiné aplikace. To může provést pouze výběr dokumentu, protože proces je mimo proces a má přístup na úrovni celého systému.
Jediný způsob, jak se dostat k dokumentu mimo kontejner aplikace, je pomocí nástroje pro výběr dokumentů a pokud je adresa URL vrácená výběrem vymezená zabezpečením. Adresa URL s vymezenou oborem zabezpečení obsahuje jenom dostatek informací k výběru dokumentu spolu s vymezenou právy požadovanými k udělení přístupu aplikace k dokumentu.
Je důležité si uvědomit, že pokud byla adresa URL s vymezeným zabezpečením serializována do řetězce a poté deserializována, informace o zabezpečení by byly ztraceny a soubor by byl nedostupný z adresy URL. Funkce Referenční dokumentace k dokumentu poskytuje mechanismus, jak se vrátit k souborům, na které tyto adresy URL odkazují.
Takže pokud aplikace získá z jednoho z referenčních dokumentů, už má připojený obor zabezpečení a lze ho použít pro NSUrl přístup k souboru. Proto důrazně doporučujeme, aby vývojář tyto informace a procesy zpracuje UIDocument za ně.
Použití záložek
Není vždy možné vytvořit výčet dokumentů aplikace, abyste se vrátili ke konkrétnímu dokumentu, například při obnovování stavu. iOS 8 poskytuje mechanismus pro vytváření záložek, které přímo cílí na daný dokument.
Následující kód vytvoří záložku z UIDocumentFileUrl vlastnosti:
// Trap all errors
try {
// Values to include in the bookmark packet
var resources = new string[] {
NSUrl.FileSecurityKey,
NSUrl.ContentModificationDateKey,
NSUrl.FileResourceIdentifierKey,
NSUrl.FileResourceTypeKey,
NSUrl.LocalizedNameKey
};
// Create the bookmark
NSError err;
Bookmark = Document.FileUrl.CreateBookmarkData (NSUrlBookmarkCreationOptions.WithSecurityScope, resources, iCloudUrl, out err);
// Was there an error?
if (err != null) {
// Yes, report it
Console.WriteLine ("Error Creating Bookmark: {0}", err.LocalizedDescription);
}
}
catch (Exception e) {
// Report error
Console.WriteLine ("Error: {0}", e.Message);
}
Existující rozhraní API záložky se používá k vytvoření záložky pro existující NSUrl , která se dá uložit a načíst, aby poskytovala přímý přístup k externímu souboru. Následující kód obnoví záložku, která byla vytvořena výše:
if (Bookmark != null) {
// Trap all errors
try {
// Yes, attempt to restore it
bool isBookmarkStale;
NSError err;
var srcUrl = new NSUrl (Bookmark, NSUrlBookmarkResolutionOptions.WithSecurityScope, iCloudUrl, out isBookmarkStale, out err);
// Was there an error?
if (err != null) {
// Yes, report it
Console.WriteLine ("Error Loading Bookmark: {0}", err.LocalizedDescription);
} else {
// Load document from bookmark
OpenDocument (srcUrl);
}
}
catch (Exception e) {
// Report error
Console.WriteLine ("Error: {0}", e.Message);
}
}
Otevření vs. režim importu a výběr dokumentu
Kontroler zobrazení pro výběr dokumentu nabízí dva různé režimy provozu:
Režim otevření – v tomto režimu, když uživatel vybere a externí dokument, výběr dokumentu vytvoří záložku s rozsahem zabezpečení v kontejneru aplikace.
Režim importu – v tomto režimu, když uživatel vybere a externí dokument, výběr dokumentu nevytvoří záložku, ale místo toho zkopíruje soubor do dočasného umístění a poskytne aplikaci přístup k dokumentu v tomto umístění:

Jakmile se aplikace z nějakého důvodu ukončí, dočasné umístění se vyprázdní a soubor se odebere. Pokud aplikace potřebuje zachovat přístup k souboru, měl by vytvořit kopii a umístit ji do kontejneru aplikace.
Režim otevření je užitečný, když aplikace chce spolupracovat s jinou aplikací a sdílet všechny změny provedené v dokumentu s touto aplikací. Režim importu se používá v případě, že aplikace nechce sdílet změny do dokumentu s jinými aplikacemi.
Vytvoření externího dokumentu
Jak bylo uvedeno výše, aplikace iOS 8 nemá přístup k kontejnerům mimo vlastní kontejner aplikace. Aplikace může zapisovat do svého vlastního kontejneru místně nebo do dočasného umístění a pak pomocí zvláštního režimu dokumentu přesunout výsledný dokument mimo kontejner aplikace do zvoleného umístění uživatele.
Chcete-li přesunout dokument do externího umístění, postupujte následovně:
- Nejprve vytvořte nový dokument v místním nebo dočasném umístění.
- Vytvořte objekt
NSUrl, který odkazuje na nový dokument. - Otevřete nový kontroler zobrazení pro výběr dokumentu a předejte ho do
NSUrlrežimuMoveToService. - Jakmile uživatel zvolí nové umístění, dokument se přesune z aktuálního umístění do nového umístění.
- Odkazový dokument se zapíše do kontejneru aplikace aplikace, aby k němu měl přístup i vytvoření aplikace.
Následující kód lze použít k přesunutí dokumentu do externího umístění: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.MoveToService);
Referenční dokument vrácený výše uvedeným procesem je přesně stejný jako ten, který byl vytvořen režimem otevření ovládacího prvku pro výběr dokumentu. Existují však situace, kdy může aplikace chtít přesunout dokument, aniž by na něj měl zacházet odkaz.
Chcete-li přesunout dokument bez generování odkazu, použijte ExportToService režim. Příklad: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.ExportToService);
Při použití ExportToService režimu se dokument zkopíruje do externího kontejneru a stávající kopie zůstane v původním umístění.
Rozšíření poskytovatelů dokumentů
S iOS 8 chce Apple koncovým uživatelům přístup k jakémukoli z jeho cloudových dokumentů bez ohledu na to, kde skutečně existují. Pro dosažení tohoto cíle nabízí iOS 8 nový mechanismus rozšíření poskytovatele dokumentu.
Co je rozšíření poskytovatele dokumentu?
Jednoduše řečeno, rozšíření poskytovatele dokumentu je způsob, jak pro vývojáře, nebo třetí straně poskytnout alternativní úložiště dokumentů aplikace, ke kterému se dá dostat stejným způsobem jako stávající umístění úložiště iCloud.
Uživatel může vybrat jedno z těchto alternativních umístění úložiště z výběru dokumentu a můžou použít přesný režim přístupu (otevřít, importovat, přesunout nebo exportovat) pro práci se soubory v tomto umístění.
To je implementováno pomocí dvou různých rozšíření:
- Rozšíření pro výběr dokumentu – poskytuje podtřídou, která uživateli poskytuje grafické rozhraní pro výběr dokumentu z alternativního umístění úložiště. Tato podtřída se zobrazí jako součást kontroleru zobrazení pro výběr dokumentu.
- Přípona souboru k dispozici – jedná se o rozšíření bez uživatelského rozhraní, které se zabývá skutečným poskytováním obsahu souborů. Tato rozšíření jsou zajištěna prostřednictvím koordinace souborů (
NSFileCoordinator). Toto je další důležité případ, kdy je potřeba koordinace souborů.
Následující diagram znázorňuje typický tok dat při práci s rozšířeními poskytovatele dokumentu:
Dojde k následujícímu procesu:
- Aplikace prezentuje kontroler pro výběr dokumentu a umožňuje uživateli vybrat soubor, se kterým bude pracovat.
- Uživatel vybere alternativní umístění souboru a zavolá se vlastní
UIViewControllerrozšíření pro zobrazení uživatelského rozhraní. - Uživatel vybere soubor z tohoto umístění a adresa URL se předává zpět do výběru dokumentu.
- Výběr dokumentu vybere adresu URL souboru a vrátí ji do aplikace, na které má uživatel pracovat.
- Do koordinátoru souboru se předává adresa URL, která vrátí obsah souborů do aplikace.
- Koordinátor souborů volá rozšíření vlastní poskytovatel souborů pro načtení souboru.
- Obsah souboru se vrátí koordinátorovi souboru.
- Obsah souboru se vrátí do aplikace.
Zabezpečení a záložky
V této části se podíváme na to, jak zabezpečení a trvalý přístup k souborům prostřednictvím záložek funguje s rozšířeními poskytovatele dokumentu. Na rozdíl od poskytovatele dokumentu iCloud, který automaticky ukládá zabezpečení a záložky do kontejneru aplikace, rozšíření pro poskytovatele dokumentu ne, protože nejsou součástí referenčního systému dokumentů.
například: v nastavení Enterprise, které poskytuje vlastní zabezpečené úložiště dat pro celé společnost, nechtějí správcům zajistit, aby byly důvěrné firemní informace dostupné nebo zpracovávané veřejnými iCloud servery. Proto nelze použít vestavěný referenční systém dokumentů.
Systém záložek je stále možné použít a je zodpovědný za rozšíření poskytovatele souborů pro správné zpracování záložky URL a vrácení obsahu dokumentu, na který odkazuje.
Pro účely zabezpečení má iOS 8 izolovanou vrstvu, která uchovává informace o tom, které aplikace mají přístup, ke kterému identifikátoru uvnitř který poskytovatel souboru patří. Je nutné poznamenat, že veškerý přístup k souborům je řízen touto vrstvou izolace.
Následující diagram znázorňuje tok dat při práci se záložkami a rozšířením poskytovatele dokumentu:
Dojde k následujícímu procesu:
- Aplikace se chystá zadat pozadí a musí uchovávat svůj stav. Volá
NSUrlk vytvoření záložky pro soubor v alternativním úložišti. NSUrlvolá rozšíření poskytovatele souborů, aby se získala trvalá adresa URL dokumentu.- Rozšíření poskytovatel souborů vrátí adresu URL jako řetězec do
NSUrl. - Sada zabalí
NSUrladresu URL do záložky a vrátí ji do aplikace. - Když aplikace běží na pozadí a potřebuje obnovit stav, předá záložku
NSUrl. NSUrlvolá rozšíření poskytovatele souboru s adresou URL souboru.- Zprostředkovatel přípon souborů přistupuje k souboru a vrátí umístění souboru do
NSUrl. - Umístění souboru je součástí sady informací o zabezpečení a vráceno do aplikace.
Odtud může aplikace získat přístup k souboru a pracovat s ním jako normální.
Zápis souborů
V této části se podíváme na to, jak zapisuje soubory do alternativního umístění s rozšířením poskytovatele dokumentu funguje. Aplikace pro iOS bude pomocí koordinace souborů ukládat informace na disk uvnitř kontejneru aplikace. Krátce po úspěšném zápisu souboru bude rozšíření poskytovatele souborů upozorněno na změnu.
V tuto chvíli může rozšíření poskytovatele souborů začít nahrávat soubor do alternativního umístění (nebo ho označit jako nečistý a vyžadovat nahrávání).
Vytváření rozšíření pro nové poskytovatele dokumentu
Vytváření rozšíření pro nové poskytovatele dokumentů je mimo rámec tohoto úvodního článku. Tady jsou uvedené informace, které ukazují, že na základě rozšíření, která uživatel zavedl do zařízení se systémem iOS, může mít aplikace přístup k umístění úložiště dokumentů mimo společnosti Apple, která poskytuje iCloud umístění.
Vývojář by měl znát tuto skutečnost při použití výběru dokumentu a práce s externími dokumenty. Neměly by předpokládat, že tento dokument je hostovaný v iCloud.
další informace o vytvoření rozšíření Storage Provider nebo pro výběr dokumentu najdete v dokumentu úvod do rozšíření aplikace .
Migrace na jednotku iCloud
V systému iOS 8 můžou uživatelé dál používat stávající systém dokumentů iCloud, který se používá v iOS 7 (a předchozích systémech), nebo se může rozhodnout migrovat existující dokumenty na nový mechanismus iCloud mechaniky.
V Mac OS X Yosemite společnost Apple neposkytuje zpětnou kompatibilitu, takže všechny dokumenty musí být migrovány na iCloud disk nebo již nebudou aktualizovány napříč zařízeními.
Po migraci účtu uživatele na disk iCloud budou moct změny dokumentů v těchto zařízeních rozšířit jenom zařízení, která používají iCloud disk.
Důležité
Vývojáři by si měli být vědomi, že nové funkce popsané v tomto článku jsou k dispozici pouze v případě, že byl účet uživatele migrován do jednotky iCloud.
Souhrn
V tomto článku jsou uvedené změny stávajících rozhraní API iCloud, která jsou nutná pro podporu iCloud jednotky a nového kontroleru zobrazení pro výběr dokumentu. Zabývá se koordinací souborů a proč je důležité při práci s cloudovým dokumentem. Pokryla se nastavení nutná pro povolení cloudových dokumentů v aplikaci Xamarin. iOS a jejich úvodní pohled na práci s dokumenty mimo kontejner aplikací aplikace pomocí nástroje pro výběr dokumentu.
Kromě toho tento článek stručně popisuje rozšíření pro poskytovatele dokumentů a proč ho by měl vývojář znát při psaní aplikací, které mohou zpracovávat cloudové dokumenty.











