async Task IndexItemAsync(IAppLinkEntry appLink) { IndexingAction indexAction = BuildIndexAction(appLink); if (_client.IsConnected && appLink.IsLinkActive) { Statuses resultStart = await AppIndex.AppIndexApi.StartAsync(_client, indexAction); if (resultStart.IsSuccess) { var aL = appLink as AppLinkEntry; if (aL != null) { aL.PropertyChanged += async (sender, e) => { if (e.PropertyName == AppLinkEntry.IsLinkActiveProperty.PropertyName) { if (appLink.IsLinkActive) { Statuses resultStartAgain = await AppIndex.AppIndexApi.StartAsync(_client, indexAction); } else { Statuses resultEnd = await AppIndex.AppIndexApi.EndAsync(_client, indexAction); } } }; } } } }
async Task IndexItemAsync(IAppLinkEntry appLink) { IndexingAction indexAction = BuildIndexAction(appLink); if (_client.IsConnected && appLink.IsLinkActive) { Statuses resultStart = await AppIndex.AppIndexApi.StartAsync(_client, indexAction); if (resultStart.IsSuccess) { var aL = appLink as AppLinkEntry; if (aL != null) { aL.PropertyChanged += async(sender, e) => { if (e.PropertyName == AppLinkEntry.IsLinkActiveProperty.PropertyName) { if (appLink.IsLinkActive) { Statuses resultStartAgain = await AppIndex.AppIndexApi.StartAsync(_client, indexAction); } else { Statuses resultEnd = await AppIndex.AppIndexApi.EndAsync(_client, indexAction); } } }; } } } }
static IndexingAction BuildIndexAction(IAppLinkEntry appLink) { Thing item = new Thing.Builder().SetName(appLink.Title).SetDescription(appLink.Description).SetUrl(global::Android.Net.Uri.Parse(appLink.AppLinkUri.AbsoluteUri)).Build(); Thing thing = new IndexingAction.Builder(IndexingAction.TypeView).SetObject(item).SetActionStatus(IndexingAction.StatusTypeCompleted).Build(); var indexAction = thing.JavaCast<IndexingAction>(); return indexAction; }
static async Task <CSSearchableItemAttributeSet> GetAttributeSet(IAppLinkEntry deepLinkUri, string contentType, string id) { #pragma warning disable CA1416 // TODO: 'CSSearchableItemAttributeSet' is unsupported on: 'ios' 14.0 and later var searchableAttributeSet = new CSSearchableItemAttributeSet(contentType) { RelatedUniqueIdentifier = id, Title = deepLinkUri.Title, ContentDescription = deepLinkUri.Description, Url = new NSUrl(deepLinkUri.AppLinkUri.ToString()) }; #pragma warning restore CA1416 if (deepLinkUri.Thumbnail != null) { using (var uiimage = await deepLinkUri.Thumbnail.GetNativeImageAsync()) { if (uiimage == null) { throw new InvalidOperationException("AppLinkEntry Thumbnail must be set to a valid source"); } searchableAttributeSet.ThumbnailData = uiimage.AsPNG(); } } return(searchableAttributeSet); }
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); }
public async void RegisterLink(IAppLinkEntry appLink) { if (string.IsNullOrWhiteSpace(appLink.AppLinkUri?.ToString())) { throw new ArgumentNullException("AppLinkUri"); } await AddLinkAsync(appLink); }
static IndexingAction BuildIndexAction(IAppLinkEntry appLink) { Thing item = new Thing.Builder().SetName(appLink.Title).SetDescription(appLink.Description).SetUrl(global::Android.Net.Uri.Parse(appLink.AppLinkUri.AbsoluteUri)).Build(); Thing thing = new IndexingAction.Builder(IndexingAction.TypeView).SetObject(item).SetActionStatus(IndexingAction.StatusTypeCompleted).Build(); var indexAction = thing.JavaCast <IndexingAction>(); return(indexAction); }
IIndexable GetIndexable(IAppLinkEntry appLink, string url) { var indexableBuilder = new IndexableBuilder(); indexableBuilder.SetName(appLink.Title); indexableBuilder.SetUrl(url); indexableBuilder.SetDescription(appLink.Description); return indexableBuilder.Build(); }
protected override void OnAppearing() { appLink = GetAppLink(BindingContext as TodoItem); if (appLink != null) { appLink.IsLinkActive = true; } }
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()) };
async void OnSaveClicked(object sender, EventArgs e) { var todoItem = (TodoItem)BindingContext; await App.Database.SaveItemAsync(todoItem); appLink = GetAppLink(BindingContext as TodoItem); Application.Current.AppLinks.RegisterLink(appLink); await Navigation.PopAsync(); }
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 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 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); var activity = new NSUserActivity($"{appDomain}.{contentType}"); 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(); } }; } }
async void OnSaveActivated(object sender, EventArgs e) { var todoItem = (TodoItem)BindingContext; if (isNewItem) { App.Database.Insert(todoItem); } else { App.Database.Update(todoItem); } appLink = GetAppLink(BindingContext as TodoItem); Application.Current.AppLinks.RegisterLink(appLink); await Navigation.PopAsync(); }
//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); }
void IndexItemAsync(IAppLinkEntry appLink) { //IndexingAction indexAction = BuildIndexAction(appLink); var url = global::Android.Net.Uri.Parse(appLink.AppLinkUri.AbsoluteUri).ToString(); IIndexable indexable = GetIndexable(appLink, url); IndexingAction indexAction = GetAction(appLink, url); /* If you’re logging an action on an item that has already been added to the index, * you don’t have to add the following update line. See * https://firebase.google.com/docs/app-indexing/android/personal-content#update-the-index for * adding content to the index */ FirebaseAppIndex.Instance.Update(indexable); GMSTask gmsTask = FirebaseUserActions.Instance .Start(indexAction) .AddOnSuccessListener(Context.GetActivity(), new AndroidActionSuccessListener(appLink as AppLinkEntry, indexAction)) .AddOnFailureListener(Context.GetActivity(), new AndroidActionFailureListener(appLink as AppLinkEntry, indexAction)); }
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()) }; using (var uiimage = await deepLinkUri.Thumbnail.GetNativeImageAsync()) { if (uiimage == null) { throw new InvalidOperationException("AppLinkEntry Thumbnail must be set to a valid source"); } searchableAttributeSet.ThumbnailData = uiimage.AsPNG(); } return(searchableAttributeSet); }
public void DeregisterLink(IAppLinkEntry appLink) { RemoveFromIndexItemAsync(appLink.AppLinkUri.ToString()); }
public async void RegisterLink(IAppLinkEntry appLink) { if (string.IsNullOrWhiteSpace(appLink.AppLinkUri?.ToString())) throw new ArgumentNullException("AppLinkUri"); await AddLinkAsync(appLink); }
public async void RegisterLink(IAppLinkEntry appLink) { await IndexItemAsync(appLink); }
//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); }
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; }
public void RegisterLink(IAppLinkEntry appLink) { IndexItemAsync(appLink); }
IndexingAction GetAction(IAppLinkEntry applink, string url) { return(Actions.NewView(applink.Title, url)); }
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; }