summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.iOS
diff options
context:
space:
mode:
authorJason Smith <jason.smith@xamarin.com>2016-04-24 12:25:26 -0400
committerRui Marinho <me@ruimarinho.net>2016-04-24 12:25:26 -0400
commit5907152c50ee2c658b266f2804e6b383bb15a6f1 (patch)
tree9beb907623359723456c5c03b08922bebc4f41f3 /Xamarin.Forms.Platform.iOS
parentfeac1ba3ed6df5e27b3fa2076bd15c190cbacd1c (diff)
downloadxamarin-forms-5907152c50ee2c658b266f2804e6b383bb15a6f1.tar.gz
xamarin-forms-5907152c50ee2c658b266f2804e6b383bb15a6f1.tar.bz2
xamarin-forms-5907152c50ee2c658b266f2804e6b383bb15a6f1.zip
Evolve feature branch (#117)
* Initial import of evolve features * [Android] Add Xamarin.Forms.Platform.Android.AppLinks project * [iOS] Fix issues with c# 6 features on iOS AppLinks * Added naive stanza to update-docs-windows.bat to produce Pages docs. Not tested. (#69) * Update packages * Add AppLinks android nuspec and fix linker issues * Fix build * Fix nusepc * Fix nuspec * Update android support nugets to 23.2.1 * Update Xamarin.UITest * Add CardView * [iOS] Fix app link for CoreSpotlight * [Android] Update AppLinks android support libs * Add Newtonsoft.Json dependency to nuspec * Fix NRE when setting ControlTemplate to null * Move to ModernHttpClient for download * Try fix build * Preserve android app links * Fix margin issue * General coding and simple fixes
Diffstat (limited to 'Xamarin.Forms.Platform.iOS')
-rw-r--r--Xamarin.Forms.Platform.iOS/FormsApplicationDelegate.cs28
-rw-r--r--Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.Classic.csproj2
-rw-r--r--Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj2
-rw-r--r--Xamarin.Forms.Platform.iOS/iOSAppIndexingProvider.cs9
-rw-r--r--Xamarin.Forms.Platform.iOS/iOSAppLinks.cs190
5 files changed, 231 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.iOS/FormsApplicationDelegate.cs b/Xamarin.Forms.Platform.iOS/FormsApplicationDelegate.cs
index a4342473..78dc6dca 100644
--- a/Xamarin.Forms.Platform.iOS/FormsApplicationDelegate.cs
+++ b/Xamarin.Forms.Platform.iOS/FormsApplicationDelegate.cs
@@ -5,10 +5,12 @@ using System.Text;
#if __UNIFIED__
using Foundation;
using UIKit;
+using CoreSpotlight;
#else
using MonoTouch.Foundation;
using MonoTouch.UIKit;
+using MonoTouch.CoreSpotlight;
#endif
namespace Xamarin.Forms.Platform.iOS
@@ -25,6 +27,7 @@ namespace Xamarin.Forms.Platform.iOS
public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
+ CheckForAppLink(userActivity);
return true;
}
@@ -77,6 +80,7 @@ namespace Xamarin.Forms.Platform.iOS
public override void UserActivityUpdated(UIApplication application, NSUserActivity userActivity)
{
+ CheckForAppLink(userActivity);
}
// from background to foreground, not yet active
@@ -121,6 +125,7 @@ namespace Xamarin.Forms.Platform.iOS
Application.Current = application;
_application = application;
+ (application as IApplicationController)?.SetAppIndexingProvider(new IOSAppIndexingProvider());
application.PropertyChanged += ApplicationOnPropertyChanged;
}
@@ -131,6 +136,29 @@ namespace Xamarin.Forms.Platform.iOS
UpdateMainPage();
}
+ void CheckForAppLink(NSUserActivity userActivity)
+ {
+ var strLink = string.Empty;
+
+ switch (userActivity.ActivityType)
+ {
+ case "NSUserActivityTypeBrowsingWeb":
+ strLink = userActivity.WebPageUrl.AbsoluteString;
+ break;
+ case "com.apple.corespotlightitem":
+ if (userActivity.UserInfo.ContainsKey(CSSearchableItem.ActivityIdentifier))
+ strLink = userActivity.UserInfo.ObjectForKey(CSSearchableItem.ActivityIdentifier).ToString();
+ break;
+ default:
+ if (userActivity.UserInfo.ContainsKey(new NSString("link")))
+ strLink = userActivity.UserInfo[new NSString("link")].ToString();
+ break;
+ }
+
+ if (!string.IsNullOrEmpty(strLink))
+ _application.SendOnAppLinkRequestReceived(new Uri(strLink));
+ }
+
void SetMainPage()
{
UpdateMainPage();
diff --git a/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.Classic.csproj b/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.Classic.csproj
index cc6aa44c..1fc4340b 100644
--- a/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.Classic.csproj
+++ b/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.Classic.csproj
@@ -144,6 +144,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Renderers\ToolbarRenderer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Renderers\WebViewRenderer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Properties\AssemblyInfo.cs" />
+ <Compile Include="iOSAppIndexingProvider.cs" />
+ <Compile Include="iOSAppLinks.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\StringResources.ar.resx" />
diff --git a/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj b/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj
index 62993b4a..dde9103e 100644
--- a/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj
+++ b/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj
@@ -144,6 +144,8 @@
<DependentUpon>StringResources.resx</DependentUpon>
</Compile>
<Compile Include="ViewInitializedEventArgs.cs" />
+ <Compile Include="IOSAppIndexingProvider.cs" />
+ <Compile Include="IOSAppLinks.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\StringResources.ar.resx" />
diff --git a/Xamarin.Forms.Platform.iOS/iOSAppIndexingProvider.cs b/Xamarin.Forms.Platform.iOS/iOSAppIndexingProvider.cs
new file mode 100644
index 00000000..88e43e54
--- /dev/null
+++ b/Xamarin.Forms.Platform.iOS/iOSAppIndexingProvider.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Xamarin.Forms.Platform.iOS
+{
+ public class IOSAppIndexingProvider : IAppIndexingProvider
+ {
+ public IAppLinks AppLinks => new IOSAppLinks();
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.iOS/iOSAppLinks.cs b/Xamarin.Forms.Platform.iOS/iOSAppLinks.cs
new file mode 100644
index 00000000..de5876b4
--- /dev/null
+++ b/Xamarin.Forms.Platform.iOS/iOSAppLinks.cs
@@ -0,0 +1,190 @@
+using System;
+using System.Threading.Tasks;
+#if __UNIFIED__
+using Foundation;
+using CoreSpotlight;
+using UIKit;
+
+#else
+using MonoTouch.Foundation;
+using MonoTouch.UIKit;
+using MonoTouch.CoreSpotlight;
+#endif
+
+namespace Xamarin.Forms.Platform.iOS
+{
+ internal class IOSAppLinks : IAppLinks
+ {
+ public async void DeregisterLink(IAppLinkEntry appLink)
+ {
+ if (string.IsNullOrWhiteSpace(appLink.AppLinkUri?.ToString()))
+ throw new ArgumentNullException("AppLinkUri");
+ await RemoveLinkAsync(appLink.AppLinkUri?.ToString());
+ }
+
+ public async void DeregisterLink(Uri uri)
+ {
+ if (string.IsNullOrWhiteSpace(uri?.ToString()))
+ throw new ArgumentNullException(nameof(uri));
+ await RemoveLinkAsync(uri.ToString());
+ }
+
+ public async void RegisterLink(IAppLinkEntry appLink)
+ {
+ if (string.IsNullOrWhiteSpace(appLink.AppLinkUri?.ToString()))
+ throw new ArgumentNullException("AppLinkUri");
+ await AddLinkAsync(appLink);
+ }
+
+ public async void DeregisterAll()
+ {
+ await ClearIndexedDataAsync();
+ }
+
+ static async Task AddLinkAsync(IAppLinkEntry deepLinkUri)
+ {
+ var appDomain = NSBundle.MainBundle.BundleIdentifier;
+ string contentType, associatedWebPage;
+ bool shouldAddToPublicIndex;
+
+ //user can provide associatedWebPage, contentType, and shouldAddToPublicIndex
+ TryGetValues(deepLinkUri, out contentType, out associatedWebPage, out shouldAddToPublicIndex);
+
+ //our unique identifier will be the only content that is common to spotlight search result and a activity
+ //this id allows us to avoid duplicate search results from CoreSpotlight api and NSUserActivity
+ //https://developer.apple.com/library/ios/technotes/tn2416/_index.html
+ var id = deepLinkUri.AppLinkUri.ToString();
+
+ var searchableAttributeSet = await GetAttributeSet(deepLinkUri, contentType, id);
+ var searchItem = new CSSearchableItem(id, appDomain, searchableAttributeSet);
+ //we need to make sure we index the item in spotlight first or the RelatedUniqueIdentifier will not work
+ await IndexItemAsync(searchItem);
+
+#if __UNIFIED__
+ var activity = new NSUserActivity($"{appDomain}.{contentType}");
+#else
+ var activity = new NSUserActivity (new NSString($"{appDomain}.{contentType}"));
+#endif
+ activity.Title = deepLinkUri.Title;
+ activity.EligibleForSearch = true;
+
+ //help increase your website url index rating
+ if (!string.IsNullOrEmpty(associatedWebPage))
+ activity.WebPageUrl = new NSUrl(associatedWebPage);
+
+ //make this search result available to Apple and to other users thatdon't have your app
+ activity.EligibleForPublicIndexing = shouldAddToPublicIndex;
+
+ activity.UserInfo = GetUserInfoForActivity(deepLinkUri);
+ activity.ContentAttributeSet = searchableAttributeSet;
+
+ //we don't need to track if the link is active iOS will call ResignCurrent
+ if (deepLinkUri.IsLinkActive)
+ activity.BecomeCurrent();
+
+ var aL = deepLinkUri as AppLinkEntry;
+ if (aL != null)
+ {
+ aL.PropertyChanged += (sender, e) =>
+ {
+ if (e.PropertyName == AppLinkEntry.IsLinkActiveProperty.PropertyName)
+ {
+ if (aL.IsLinkActive)
+ activity.BecomeCurrent();
+ else
+ activity.ResignCurrent();
+ }
+ };
+ }
+ }
+
+ static Task<bool> ClearIndexedDataAsync()
+ {
+ var tcs = new TaskCompletionSource<bool>();
+ if (CSSearchableIndex.IsIndexingAvailable)
+ CSSearchableIndex.DefaultSearchableIndex.DeleteAll(error => tcs.TrySetResult(error == null));
+ else
+ tcs.TrySetResult(false);
+ return tcs.Task;
+ }
+
+ static async Task<CSSearchableItemAttributeSet> GetAttributeSet(IAppLinkEntry deepLinkUri, string contentType, string id)
+ {
+ var searchableAttributeSet = new CSSearchableItemAttributeSet(contentType)
+ {
+ RelatedUniqueIdentifier = id,
+ Title = deepLinkUri.Title,
+ ContentDescription = deepLinkUri.Description,
+ Url = new NSUrl(deepLinkUri.AppLinkUri.ToString())
+ };
+
+ var source = deepLinkUri.Thumbnail;
+ IImageSourceHandler handler;
+ if (source != null && (handler = Registrar.Registered.GetHandler<IImageSourceHandler>(source.GetType())) != null)
+ {
+ UIImage uiimage;
+ try
+ {
+ uiimage = await handler.LoadImageAsync(source);
+ }
+ catch (OperationCanceledException)
+ {
+ uiimage = null;
+ }
+ searchableAttributeSet.ThumbnailData = uiimage.AsPNG();
+ uiimage.Dispose();
+ }
+
+ return searchableAttributeSet;
+ }
+
+ static NSMutableDictionary GetUserInfoForActivity(IAppLinkEntry deepLinkUri)
+ {
+ //this info will only appear if not from a spotlight search
+ var info = new NSMutableDictionary();
+ info.Add(new NSString("link"), new NSString(deepLinkUri.AppLinkUri.ToString()));
+ foreach (var item in deepLinkUri.KeyValues)
+ info.Add(new NSString(item.Key), new NSString(item.Value));
+ return info;
+ }
+
+ static Task<bool> IndexItemAsync(CSSearchableItem searchItem)
+ {
+ var tcs = new TaskCompletionSource<bool>();
+ if (CSSearchableIndex.IsIndexingAvailable)
+ {
+ CSSearchableIndex.DefaultSearchableIndex.Index(new[] { searchItem }, error => tcs.TrySetResult(error == null));
+ }
+ else
+ tcs.SetResult(false);
+ return tcs.Task;
+ }
+
+ static Task<bool> RemoveLinkAsync(string identifier)
+ {
+ var tcs = new TaskCompletionSource<bool>();
+ if (CSSearchableIndex.IsIndexingAvailable)
+ CSSearchableIndex.DefaultSearchableIndex.Delete(new[] { identifier }, error => tcs.TrySetResult(error == null));
+ else
+ tcs.SetResult(false);
+ return tcs.Task;
+ }
+
+ //Parse the KeyValues because user can provide associatedWebPage, contentType, and shouldAddToPublicIndex options
+ static void TryGetValues(IAppLinkEntry deepLinkUri, out string contentType, out string associatedWebPage, out bool shouldAddToPublicIndex)
+ {
+ contentType = string.Empty;
+ associatedWebPage = string.Empty;
+ shouldAddToPublicIndex = false;
+ var publicIndex = string.Empty;
+
+ if (!deepLinkUri.KeyValues.TryGetValue(nameof(contentType), out contentType))
+ contentType = "View";
+
+ if (deepLinkUri.KeyValues.TryGetValue(nameof(publicIndex), out publicIndex))
+ bool.TryParse(publicIndex, out shouldAddToPublicIndex);
+
+ deepLinkUri.KeyValues.TryGetValue(nameof(associatedWebPage), out associatedWebPage);
+ }
+ }
+} \ No newline at end of file