diff --git a/docs/Firebase/AdMob/Details.md b/docs/Firebase/AdMob/Details.md deleted file mode 100755 index 33e7f12cb..000000000 --- a/docs/Firebase/AdMob/Details.md +++ /dev/null @@ -1,22 +0,0 @@ -AdMob by Google is an easy way to monetize mobile apps with targeted, in-app advertising. - -AdMob by Google is a mobile advertising platform that you can use to generate revenue from your app. Using AdMob with Firebase Analytics provides you with additional app usage data and analytics capabilities. - -## Key capabilities - -| | | -|:-:|-| -| **Earn more from AdMob's in-app ads** | Show ads from millions of Google advertisers in real time, or use AdMob Mediation to earn from over 40 premium networks through the AdMob platform to simplify your ad operations, improve competition, and earn more, for free. AdMob mediation has [ad network optimization](https://support.google.com/admob/answer/3379794) built in, which automatically adjusts the positions of your other ad networks in your mediation stack to ensure you maximize your revenue. | -| **Improve user experience** | Native and video ads create a positive user experience as you monetize by matching the look and feel of your app. Choose from different ad templates, customize them, and experiment with different layouts on the fly without republishing your app. | -| **Scale fast** | When your app's a global or domestic hit, you can monetize users quickly with AdMob, by showing ads to users in more than 200 markets. More than one app? AdMob house ads is a free tool that enables you to cross-promote your apps to your userbase, across your family of apps. | -| **Access monetization reports** | AdMob is the premier monetization platform for mobile. While generating ad revenue, AdMob also produces its own monetization reports that you can use to make smarter decisions about product strategy. | - -## How does it work? - -AdMob by Google helps you monetize your mobile app through in-app advertising. Ads can be displayed as banner ads, interstitial ads, video ads, or native ads — which are seamlessly added to platform native UI components. On Android, you can additionally display in-app purchase ads, which allow users to purchase advertised products from within your app. - -Before you can display ads within your app, you'll need to create an AdMob account and activate one or more Ad Unit IDs. This is a unique identifier for the places in your app where ads are displayed. If you are already using AdMob in your app, all of your existing Ad Unit IDs continue to work after you've added Firebase to your app. - -AdMob uses the Google Mobile Ads SDK. The Google Mobile Ads SDK helps app developers gain insights about their users, drive more in-app purchases, and maximize ad revenue. In order to do so, the default integration of the Mobile Ads SDK collects information such as device information, publisher-provided location information, and general in-app purchase information such as item purchase price and currency. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/admob/) to see original Firebase documentation._ \ No newline at end of file diff --git a/docs/Firebase/AdMob/GettingStarted.md b/docs/Firebase/AdMob/GettingStarted.md deleted file mode 100755 index 4ce619ab2..000000000 --- a/docs/Firebase/AdMob/GettingStarted.md +++ /dev/null @@ -1,2230 +0,0 @@ -# Table of content - -- [Table of content](#table-of-content) -- [Get Started](#get-started) - - [Use Google Mobile Ads SDK without Firebase](#use-google-mobile-ads-sdk-without-firebase) - - [Add Firebase to your app](#add-firebase-to-your-app) - - [Configure AdMob in your app](#configure-admob-in-your-app) - - [Initialize the Google Mobile Ads SDK](#initialize-the-google-mobile-ads-sdk) - - [Always test with test ads](#always-test-with-test-ads) -- [Banner Ads](#banner-ads) - - [Create a BannerView](#create-a-bannerview) - - [Interface Builder](#interface-builder) - - [Programmatically](#programmatically) - - [Configure BannerView properties](#configure-bannerview-properties) - - [Call LoadRequest method](#call-loadrequest-method) - - [Ad events](#ad-events) - - [Registering for banner events using IBannerViewDelegate interface](#registering-for-banner-events-using-ibannerviewdelegate-interface) - - [Implementing banner events](#implementing-banner-events) - - [Use cases](#use-cases) - - [Adding a banner to the view hierarchy once an ad is received](#adding-a-banner-to-the-view-hierarchy-once-an-ad-is-received) - - [Animating a banner ad](#animating-a-banner-ad) - - [Pausing and resuming the app](#pausing-and-resuming-the-app) - - [Banner sizes](#banner-sizes) - - [Smart Banners](#smart-banners) -- [Interstitial Ads](#interstitial-ads) - - [Create a Interstitial object](#create-a-interstitial-object) - - [Load an ad](#load-an-ad) - - [Show the ad](#show-the-ad) - - [Use IInterstitialDelegate interface or Interstitial events to reload](#use-iinterstitialdelegate-interface-or-interstitial-events-to-reload) - - [Ad events](#ad-events) - - [Registering for interstitial events using IInterstitialDelegate interface](#registering-for-interstitial-events-using-iinterstitialdelegate-interface) - - [Implementing interstitial events](#implementing-interstitial-events) - - [Some best practices](#some-best-practices) - - [Consider whether interstitial ads are the right type of ad for your app.](#consider-whether-interstitial-ads-are-the-right-type-of-ad-for-your-app) - - [Remember to pause the action when displaying an interstitial ad.](#remember-to-pause-the-action-when-displaying-an-interstitial-ad) - - [Allow for adequate loading time.](#allow-for-adequate-loading-time) - - [Don't flood the user with ads.](#dont-flood-the-user-with-ads) - - [Don't use the `InterstitialDelegate.DidReceiveAd` or `Interstitial.AdReceived` events to show the interstitial.](#dont-use-the-interstitialdelegatedidreceivead-or-interstitialadreceived-events-to-show-the-interstitial) -- [Native Ads Advanced (Unified)](#native-ads-advanced-unified) - - [Loading ads](#loading-ads) - - [Initialize the ad loader](#initialize-the-ad-loader) - - [Implement the ad loader delegate](#implement-the-ad-loader-delegate) - - [Request the ad](#request-the-ad) - - [When to request ads](#when-to-request-ads) - - [Determining when loading has finished](#determining-when-loading-has-finished) - - [Handling failed requests](#handling-failed-requests) - - [Get notified of native ad events](#get-notified-of-native-ad-events) - - [Native ad options](#native-ad-options) - - [`NativeAdViewOptions`](#nativeadviewoptions) - - [`VideoOptions`](#videooptions) - - [`MultipleAdsAdLoaderOptions`](#multipleadsadloaderoptions) - - [Displaying a system-defined native ad format](#displaying-a-system-defined-native-ad-format) - - [UnifiedNativeAdView](#unifiednativeadview) - - [The AdChoices overlay](#the-adchoices-overlay) - - [Ad attribution](#ad-attribution) - - [Native video](#native-video) - - [MediaView](#mediaview) - - [VideoController](#videocontroller) -- [Native Ads Advanced](#native-ads-advanced) - - [Loading ads](#loading-ads) - - [Initialize a AdLoader](#initialize-a-adloader) - - [Implement the ad loader delegate](#implement-the-ad-loader-delegate) - - [Request the ad](#request-the-ad) - - [When to request ads](#when-to-request-ads) - - [Determining when loading has finished](#determining-when-loading-has-finished) - - [Handling failed requests](#handling-failed-requests) - - [Get notified of native ad events](#get-notified-of-native-ad-events) - - [Native ad options](#native-ad-options) - - [`NativeAdViewOptions`](#nativeadviewoptions) - - [`VideoOptions`](#videooptions) - - [`MultipleAdsAdLoaderOptions`](#multipleadsadloaderoptions) - - [Displaying a system-defined native ad format](#displaying-a-system-defined-native-ad-format) - - [The ad view classes](#the-ad-view-classes) - - [The AdChoices overlay](#the-adchoices-overlay) - - [Ad attribution](#ad-attribution) - - [Native video](#native-video) - - [MediaView](#mediaview) - - [VideoController](#videocontroller) -- [Rewarded Video Ads](#rewarded-video-ads) - - [Request rewarded video](#request-rewarded-video) - - [Set up event notifications](#set-up-event-notifications) - - [Display rewarded video](#display-rewarded-video) - - [Reload a rewarded video](#reload-a-rewarded-video) -- [Targeting](#targeting) - - [Request](#request) - - [Location](#location) - - [Child-directed setting](#child-directed-setting) - - [Users under the age of consent](#users-under-the-age-of-consent) - - [Ad content filtering](#ad-content-filtering) - - [Content URL](#content-url) - - [Load an ad with targeting](#load-an-ad-with-targeting) - - [FAQ](#faq) -- [Reporting](#reporting) -- [Global Settings](#global-settings) - - [Video ad volume control](#video-ad-volume-control) - - [Changing audio session](#changing-audio-session) - - [In-app purchase reporting](#in-app-purchase-reporting) - - [Crash reporting](#crash-reporting) -- [Requesting Consent from European Users](#requesting-consent-from-european-users) - - [Tips for using the Consent SDK](#tips-for-using-the-consent-sdk) - - [If you select 12 or fewer ad technology providers and don't use mediation](#if-you-select-12-or-fewer-ad-technology-providers-and-dont-use-mediation) - - [If you select more than 12 ad technology providers and don't use mediation](#if-you-select-more-than-12-ad-technology-providers-and-dont-use-mediation) - - [If you use AdMob mediation](#if-you-use-admob-mediation) - - [Update consent status](#update-consent-status) - - [Collect consent](#collect-consent) - - [Google-rendered consent form](#google-rendered-consent-form) - - [Load consent form](#load-consent-form) - - [Show consent form](#show-consent-form) - - [Publisher-managed consent collection](#publisher-managed-consent-collection) - - [Storing publisher managed consent](#storing-publisher-managed-consent) - - [Change or revoke consent](#change-or-revoke-consent) - - [Users under the age of consent](#users-under-the-age-of-consent) - - [Testing](#testing) - - [Forward consent to the Google Mobile Ads SDK](#forward-consent-to-the-google-mobile-ads-sdk) - - [FAQ](#faq) - -# Get Started - -AdMob uses the Google Mobile Ads SDK. The Google Mobile Ads SDK helps app developers gain insights about their users, drives more in-app purchases, and maximizes ad revenue. To do so, the default integration of the Mobile Ads SDK collects information such as device information, publisher-provided location information, and general in-app purchase information (such as item purchase price and currency). - -> ![note_icon] **_Note: The Mobile Ads SDK does not collect payment card information._** - -## Use Google Mobile Ads SDK without Firebase - -If you don't plan to include Firebase in your app, you can use Google Mobile Ads SDK as standalone. To do so, just install the `Xamarin.Google.iOS.MobileAds` NuGet and jump to [Initialize the Google Mobile Ads SDK section](#Initialize-the-Google-Mobile-Ads-SDK) directly. - -## Add Firebase to your app - -1. Create a Firebase project in the [Firebase console][1], if you don't already have one. If you already have an existing Google project associated with your mobile app, click **Import Google Project**. Otherwise, click **Create New Project**. -2. Click **Add Firebase to your iOS app** and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just [download the config file][2]. -3. When prompted, enter your app's bundle ID. It's important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project. -4. At the end, you'll download a `GoogleService-Info.plist` file. You can [download this file][2] again at any time. -5. In [Firebase console][1], go to AdMob section and link your recently created app to AdMob. - -## Configure AdMob in your app - -Once you have your `GoogleService-Info.plist` file downloaded in your computer, do the following steps in Xamarin Studio: - -1. Add `GoogleService-Info.plist` file to your app project. -2. Set `GoogleService-Info.plist` **build action** behaviour to `Bundle Resource` by Right clicking/Build Action. -3. Open `GoogleService-Info.plist` file and change `IS_ADS_ENABLED` value to `Yes`. -4. Add the following line of code somewhere in your app, typically in your AppDelegate's `FinishedLaunching` method (don't forget to import `Firebase.Core` namespace): - -```csharp -App.Configure (); -``` - -## Initialize the Google Mobile Ads SDK - -At app launch, initialize the Google Mobile Ads SDK by calling `Configure` method: - -```csharp -// Get your Application Id here: https://apps.admob.com/#account/appmgmt: -MobileAds.Configure ("ca-app-pub-XXXXXXXXXXXXXXXX~NNNNNNNNNN"); -``` - -Initializing the Google Mobile Ads SDK at app launch allows the SDK to fetch app-level settings and perform configuration tasks as early as possible. This can help reduce latency for the initial ad request. Initialization requires an app ID. App IDs are unique identifiers given to mobile apps when they're registered in the AdMob console. - -To find your app ID, click the [App management][3] option under the settings dropdown (located in the upper right hand corner) on the AdMob account page. App IDs have the form **ca-app-pub-XXXXXXXXXXXXXXXX~NNNNNNNNNN**. - -### Always test with test ads - -The sample code in these guides contains an ad unit ID and you're free to request ads with it. It's been specially configured to return test ads rather than production ads for every request, which makes it safe to use. - -However, once you register an app in the AdMob UI and create your own ad unit IDs for use in your app, you'll need to explicitly configure your device as a test device when you're developing. **This is extremely important**. Testing with real ads (even if you never tap on them) is against AdMob policy and can cause your account to be suspended. See Test Ads for information on how you can make sure you always get test ads when developing. - ---- - -# Banner Ads - -Banner ads are rectangular image or text ads that occupy a spot within an app's layout. They stay on screen while users are interacting with the app, and can refresh automatically after a certain period of time. If you're new to mobile advertising, they're a great place to start. - -This guide shows you how to integrate banner ads from AdMob into an iOS app. In addition to code snippets and instructions, it includes information about sizing banners properly and links to additional resources. - -## Create a BannerView - -AdMob banners are displayed in `BannerView` objects, so the first step toward integrating AdMob ads is to include a `BannerView` in your view hierarchy. This is typically done in one of two ways. - -### Interface Builder - -A `BannerView` can be added to a storyboard or xib file like any typical view. When using this method, be sure to add **width** and **height** constraints to match the ad size you'd like to display. For example, when displaying a standard banner (320x50), use a width constraint of 320 points, and a height constraint of 50 points. - -### Programmatically - -A BannerView can also be instantiated directly. Here's an example of how to create a BannerView with the standard banner size of 320x50: - -```csharp -using Google.MobileAds; - -namespace YourNamespace -{ - public class YourViewController - { - BannerView bannerView; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - - bannerView = new BannerView (AdSizeCons.Banner); - View.AddSubview (bannerView); - } - } -} -``` - -## Configure BannerView properties - -In order to load and display ads, `BannerView` requires a few properties be set. - -* RootViewController: This view controller is used to present an overlay when the ad is clicked. It should normally be set to the view controller that contains the `BannerView`. -* AdUnitID: This is the AdMob ad unit ID from which the `BannerView` should load ads. - -Here's a code example showing how to set the two properties in the `ViewDidLoad` method of a `UIViewController`: - -```csharp -public override void ViewDidLoad () -{ - base.ViewDidLoad (); - - /// - bannerView = new BannerView (AdSizeCons.Banner) { - AdUnitID = "ca-app-pub-3940256099942544/2934735716", - RootViewController = this - }; - /// - - View.AddSubview (bannerView); -} -``` - -> ![note_icon] Note: Ad unit IDs are created in the AdMob UI, and represent a place in your app where ads appear. If you show banner ads in two view controllers, for example, you can create an ad unit for each one. - -## Call LoadRequest method - -Once the `BannerView` is in place and its properties configured, it's time to load an ad. This is done by calling the `LoadRequest` method, which takes a `Request` object as its argument: - -```csharp -public override void ViewDidLoad () -{ - base.ViewDidLoad (); - - bannerView = new BannerView (AdSizeCons.Banner) { - AdUnitID = "ca-app-pub-3940256099942544/2934735716", - RootViewController = this - }; - View.AddSubview (bannerView); - - /// - bannerView.LoadRequest (Request.GetDefaultRequest ()); - /// -} -``` - -`Request` objects represent a single ad request, and contain properties for things like targeting information. - -## Ad events - -Through the use of `IBannerViewDelegate` interface or `BannerView` object events, you can listen for lifecycle events, such as when an ad is closed or the user leaves the app. If you decide to use Ad events, you must use the `IBannerViewDelegate` interface or `BannerView` object events, you cannot use both or create a mix of them. If you plan to use `BannerView` object events, you can jump to [Implementing banner events section](#Implementing-banner-events) directly. - -### Registering for banner events using IBannerViewDelegate interface - -To register for banner ad events using `IBannerViewDelegate` interface, set the `Delegate` property on `BannerView` to an object that implements the `IBannerViewDelegate` interface. Generally, the class that implements banner ads also acts as the delegate class, in which case, the `Delegate` property can be set to `this`: - -```csharp -public class YourViewController : UIViewController, IBannerViewDelegate -{ - BannerView bannerView; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - - bannerView = new BannerView (AdSizeCons.Banner) { - AdUnitID = "ca-app-pub-3940256099942544/2934735716", - RootViewController = this - }; - View.AddSubview (bannerView); - - /// - bannerView.Delegate = this; - /// - } -} -``` - -### Implementing banner events - -Each of the methods in `IBannerViewDelegate` interface are marked as **optional**, so you only need to implement the methods you need. This also applies for `BannerView` object events, you only need to implement the events you need. This example implements each method and event and logs a message to the console: - -```csharp -// For Console class -using System; -// For Export attribute -using Fundation; - -/// Tells the delegate an ad request loaded an ad. -[Export ("adViewDidReceiveAd:")] -public void DidReceiveAd (BannerView view) -{ - Console.WriteLine ($"{nameof (DidReceiveAd)} method."); -} - -bannerView.AdReceived += (sender, e) => { - Console.WriteLine ("AdReceived event."); -}; - -/// Tells the delegate an ad request failed. -[Export ("adView:didFailToReceiveAdWithError:")] -public void DidFailToReceiveAd (BannerView view, RequestError error) -{ - Console.WriteLine ($"{nameof (DidFailToReceiveAd)} method with error: {error.LocalizedDescription}."); -} - -bannerView.ReceiveAdFailed += (sender, e) => { - Console.WriteLine ($"ReceiveAdFailed event with error: {e.Error.LocalizedDescription}."); -}; - -/// Tells the delegate that a full screen view will be presented in response -/// to the user clicking on an ad. -[Export ("adViewWillPresentScreen:")] -public void WillPresentScreen (BannerView adView) -{ - Console.WriteLine ($"{nameof (WillPresentScreen)} method."); -} - -bannerView.WillPresentScreen += (sender, e) => { - Console.WriteLine ("WillPresentScreen event."); -}; - -/// Tells the delegate that the full screen view will be dismissed. -[Export ("adViewWillDismissScreen:")] -public void WillDismissScreen (BannerView adView) -{ - Console.WriteLine ($"{nameof (WillDismissScreen)} method."); -} - -bannerView.WillDismissScreen += (sender, e) => { - Console.WriteLine ("WillDismissScreen event."); -}; - -/// Tells the delegate that the full screen view has been dismissed. -[Export ("adViewDidDismissScreen:")] -public void DidDismissScreen (BannerView adView) -{ - Console.WriteLine ($"{nameof (DidDismissScreen)} method."); -} - -bannerView.ScreenDismissed += (sender, e) => { - Console.WriteLine ("ScreenDismissed event."); -}; - -/// Tells the delegate that a user click will open another app (such as -/// the App Store), backgrounding the current app. -[Export ("adViewWillLeaveApplication:")] -public void WillLeaveApplication (BannerView adView) -{ - Console.WriteLine ($"{nameof (WillLeaveApplication)} method."); -} - -bannerView.WillLeaveApplication += (sender, e) => { - Console.WriteLine ("WillLeaveApplication event."); -}; -``` - -## Use cases - -Here are some example use cases for these ad event methods. - -### Adding a banner to the view hierarchy once an ad is received - -You may choose to hold off on adding a `BannerView` to the view hierarchy until an ad is received. You can do this by listening for the `DidReceiveAd`/`AdReceived` event: - -```csharp -[Export ("adViewDidReceiveAd:")] -public void DidReceiveAd (BannerView view) -{ - View.AddSubview (bannerView); -} - -// or - -bannerView.AdReceived += (sender, e) => { - View.AddSubview (bannerView); -}; -``` - -The `AddSubview` method automatically removes a view from its parent if it already has one, so it's safe to make this call every time. - -### Animating a banner ad - -You can also use the `DidReceiveAd`/`AdReceived` event to animate a banner ad once it's returned as shown in the following example: - -```csharp -[Export ("adViewDidReceiveAd:")] -public void DidReceiveAd (BannerView view) -{ - bannerView.Alpha = 0; - UIView.Animate (1, () => bannerView.Alpha = 1); -} - -// or - -bannerView.AdReceived += (sender, e) => { - bannerView.Alpha = 0; - UIView.Animate (1, () => bannerView.Alpha = 1); -}; -``` - -### Pausing and resuming the app - -The `IBannerViewDelegate` interface has methods to notify you of events such as when a click causes an overlay to be presented or dismissed, or invokes an external browser. Same functionality applies for `BannerView` events. If you want to know that these events happened because of ads, then register for these `IBannerViewDelegate` methods or `BannerView` events. - -But to catch all types of overlay presentations or external browser invocations, not just ones that come from ad clicks, your app is better off listening for the equivalent methods on `UIViewController` or `UIApplication`. Here is a table showing the equivalent iOS methods that are invoked at the same time as GADBannerViewDelegate methods: - -| IBannerViewDelegate method/BannerView event | iOS method | -|:-------------------------------------------------:|:----------------------------------------------:| -| **WillPresentScreen**/**WillPresentScreen** | UIViewController's **ViewWillDisappear** | -| **WillDismissScreen**/**WillDismissScreen** | UIViewController's **ViewWillAppear** | -| **DidDismissScreen**/**ScreenDismissed** | UIViewController's **ViewDidAppear** | -| **WillLeaveApplication**/**WillLeaveApplication** | UIApplicationDelegate's **DidEnterBackground** | - -## Banner sizes - -The following banner sizes are supported: - -| Size (WxH) | Description | Availability | AdSize constant | -|:-----------------------:|:--------------------:|:--------------------:|:-------------------------------------------------------------:| -| 320x50 | Standard banner | Phones and tablets | kGADAdSizeBanner | -| 320x100 | Large banner | Phones and tablets | kGADAdSizeLargeBanner | -| 300x250 | IAB medium rectangle | Phones and tablets | kGADAdSizeMediumRectangle | -| 468x60 | IAB full-size banner | Tablets | kGADAdSizeFullBanner | -| 728x90 | IAB leaderboard | Tablets | kGADAdSizeLeaderboard | -| Screen width x 32,50,90 | Smart banner | Phones and tablets | kGADAdSizeSmartBannerPortrait, kGADAdSizeSmartBannerLandscape | - -If an app tries to load a banner that's too big for its layout, the SDK won't display it. Instead, an error message will be written to the log. - -## Smart Banners - -Smart Banners are ad units that render screen-wide banner ads on any screen size across different devices in either orientation. Smart Banners help deal with increasing screen fragmentation across different devices by "smartly" detecting the width of the phone in its current orientation, and making the ad view that size. - -Smart Banners on iPhones have a height of 50 points in portrait and 32 points in landscape. On iPads, height is 90 points in both portrait and landscape. - -When an image ad isn't large enough to take up the entire allotted space, the image will be centered, and the space on either side will be filled in. - -To use Smart Banners, just specify `AdSizeCons.SmartBannerPortrait` or `AdSizeCons.SmartBannerLandscape` for the ad size: - -```csharp -BannerView bannerView = new BannerView (AdSizeCons.SmartBannerPortrait); -``` - -Since the addition of the safe area for iOS 11, for full-width banners you should also add constraints for the edges of the banner to the edges of the safe area. - ---- - -# Interstitial Ads - -Interstitial ads are full-screen ads that are overlaid on top of an app. They are generally displayed at natural app transition points such as in between game levels. When an app shows an interstitial ad, the user has the choice to either tap on the ad and continue to its destination or close it and return to the app. - -This guide shows you how to integrate interstitials from AdMob into an iOS app. - -## Create a Interstitial object -Interstitials ads are requested and shown by `Interstitial` objects. The first step in using one is to instantiate it and set its ad unit ID. For example, here's how to create an `Interstitial` in the `ViewDidLoad` method of a `UIViewController`: - -```csharp -using Google.MobileAds; - -namespace YourNamespace -{ - public class YourViewController : UIViewController - { - Interstitial interstitial; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - interstitial = new Interstitial ("ca-app-pub-3940256099942544/4411468910"); - } - } -} -``` - -`Interstitial` is a single-use object that will load and display one interstitial ad. To display multiple interstitial ads, an app needs to create an `Interstitial` object for each one. - -## Load an ad - -To load an interstitial, call the `Interstitial` object's `LoadRequest` method. This method accepts a `Request` object as its single argument: - -```csharp -public override void ViewDidLoad () -{ - base.ViewDidLoad (); - interstitial = new Interstitial ("ca-app-pub-3940256099942544/4411468910"); - - /// - interstitial.LoadRequest (Request.GetDefaultRequest ()); - /// -} -``` - -## Show the ad - -Interstitials should be displayed during natural pauses in the flow of an app. Between levels of a game is a good example, or after the user completes a task. To show an interstitial, check the `IsReady` property on `Interstitial` instance to verify that it's done loading, then call `PresentFromRootViewController` method. Here's an example of how to do this in one of the action methods in a `UIViewController`: - -```csharp -public void DoSomething (NSObject sender) -{ - // ... - - if (interstitial.IsReady) - interstitial.PresentFromRootViewController (this); - else - Console.WriteLine ("Ad wasn't ready..."); -} -``` - -The message **"Cannot present interstitial. It is not ready"** indicates that the interstitial is still loading or has failed to load. To avoid this warning, use the `IsReady` property to check if the interstitial ad is ready to be presented prior to calling `PresentFromRootViewController` method. - -## Use IInterstitialDelegate interface or Interstitial events to reload - -`Interstitial` is a one-time-use object. That means once an interstitial is shown, `HasBeenUsed` property returns `true` and the interstitial can't be used to load another ad. To request another interstitial, you'll need to create a new `Interstitial` object. If you try to re-use an interstitial object, you'll get the error **"Request Error: Will not send request because interstitial object has been used"**. - -The best place to allocate another interstitial is in the `DidDismissScreen` method of the `IInterstitialDelegate` interface so that the next interstitial starts loading as soon as the previous one is dismissed. You may even consider breaking out interstitial initialization into its own helper method: - -```csharp -// For Export attribute -using Foundation; -using Google.MobileAds; - -namespace YourNamespace -{ - public class YourViewController : UIViewController, IInterstitialDelegate - { - Interstitial interstitial; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - interstitial = CreateAndLoadInterstitial (); - } - - Interstitial CreateAndLoadInterstitial () - { - var newInterstitial = new Interstitial ("ca-app-pub-3940256099942544/4411468910") { - Delegate = this - }; - newInterstitial.LoadRequest (Request.GetDefaultRequest ()); - return newInterstitial; - } - - [Export ("interstitialDidDismissScreen:")] - public void DidDismissScreen (Interstitial ad) - { - interstitial = CreateAndLoadInterstitial (); - } - } -} -``` - -You can achieve the same result using `Interstitial` events: - -```csharp -using Google.MobileAds; - -namespace YourNamespace -{ - public class YourViewController : UIViewController - { - Interstitial interstitial; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - interstitial = CreateAndLoadInterstitial (); - } - - Interstitial CreateAndLoadInterstitial () - { - var newInterstitial = new Interstitial ("ca-app-pub-3940256099942544/4411468910"); - newInterstitial.ScreenDismissed += NewInterstitial_ScreenDismissed; - newInterstitial.LoadRequest (Request.GetDefaultRequest ()); - return newInterstitial; - } - - void NewInterstitial_ScreenDismissed (object sender, EventArgs e) - { - interstitial = CreateAndLoadInterstitial (); - } - } -} -``` - -By preloading another interstitial immediately after the previous one is dismissed, your app is prepared to show an interstitial again at the next logical break point. - -## Ad events - -Through the use of `IInterstitialDelegate` interface or `Interstitial` object events, you can listen for lifecycle events, such as when an ad is closed or the user leaves the app. If you decide to use Ad events, you must use the `IInterstitialDelegate` interface or `Interstitial` object events, you cannot use both or create a mix of them. - -### Registering for interstitial events using IInterstitialDelegate interface - -To register for interstitial ad events, set the `Delegate` property on `Interstitial` to an object that implements the `IInterstitialDelegate`interface. Generally, the class that implements interstitial ads also acts as the delegate class, in which case the `Delegate` property can be set to `this` as follows: - -```csharp -// For Export attribute -using Google.MobileAds; - -namespace YourNamespace -{ - public class YourViewController : UIViewController, IInterstitialDelegate - { - Interstitial interstitial; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - interstitial = new Interstitial ("ca-app-pub-3940256099942544/4411468910") { - Delegate = this - }; - } - } -} -``` - -### Implementing interstitial events - -Each of the methods in `IInterstitialDelegate` interface are marked as **optional**, so you only need to implement the methods you need. This also applies for `Interstitial` object events, you only need to implement the events you need. This example implements each method and logs a message to the console: - -```csharp -// For Console class -using System; -// For Export attribute -using Fundation; - -/// Tells the delegate an ad request succeeded. -[Export ("interstitialDidReceiveAd:")] -public void DidReceiveAd (Interstitial ad) -{ - Console.WriteLine ($"{nameof (DidReceiveAd)} method."); -} - -interstitial.AdReceived += (sender, e) => { - Console.WriteLine ("AdReceived event."); -}; - -/// Tells the delegate an ad request failed. -[Export ("interstitial:didFailToReceiveAdWithError:")] -public void DidFailToReceiveAd (Interstitial sender, RequestError error) -{ - Console.WriteLine ($"{nameof (DidFailToReceiveAd)} method with error: {error.LocalizedDescription}."); -} - -interstitial.ReceiveAdFailed += (sender, e) => { - Console.WriteLine ($"ReceiveAdFailed event with error: {e.Error.LocalizedDescription}."); -}; - -/// Tells the delegate that an interstitial will be presented. -[Export ("interstitialWillPresentScreen:")] -public void WillPresentScreen (Interstitial ad) -{ - Console.WriteLine ($"{nameof (WillPresentScreen)} method."); -} - -interstitial.WillPresentScreen += (sender, e) => { - Console.WriteLine ("WillPresentScreen event."); -}; - -/// Tells the delegate the interstitial failed to present. -[Export ("interstitialDidFailToPresentScreen:")] -public void DidFailToPresentScreen (Interstitial ad) -{ - Console.WriteLine ($"{nameof (DidFailToPresentScreen)} method."); -} - -interstitial.FailedToPresentScreen += (sender, e) => { - Console.WriteLine ("FailedToPresentScreen event."); -}; - -/// Tells the delegate the interstitial is to be animated off the screen. -[Export ("interstitialWillDismissScreen:")] -public void WillDismissScreen (Interstitial ad) -{ - Console.WriteLine ($"{nameof (WillDismissScreen)} method."); -} - -interstitial.WillDismissScreen += (sender, e) => { - Console.WriteLine ("WillDismissScreen event."); -}; - -/// Tells the delegate the interstitial had been animated off the screen. -[Export ("interstitialDidDismissScreen:")] -public void DidDismissScreen (Interstitial ad) -{ - Console.WriteLine ($"{nameof (DidDismissScreen)} method."); -} - -interstitial.ScreenDismissed += (sender, e) => { - Console.WriteLine ("ScreenDismissed event."); -}; - -/// Tells the delegate that a user click will open another app -/// (such as the App Store), backgrounding the current app. -[Export ("interstitialWillLeaveApplication:")] -public void WillLeaveApplication (Interstitial ad) -{ - Console.WriteLine ($"{nameof (WillLeaveApplication)} method."); -} - -interstitial.WillLeaveApplication += (sender, e) => { - Console.WriteLine ("WillLeaveApplication event."); -}; -``` - -## Some best practices - -### Consider whether interstitial ads are the right type of ad for your app. - -Interstitial ads work best in apps with natural transition points. The conclusion of a task within an app, like sharing an image or completing a game level, creates such a point. Because the user is expecting a break in the action, it's easy to present an interstitial ad without disrupting their experience. Make sure you consider at which points in your app's workflow you'll display interstitial ads and how the user is likely to respond. - -### Remember to pause the action when displaying an interstitial ad. - -There are a number of different types of interstitial ads: text, image, video, and more. It's important to make sure that when your app displays an interstitial ad, it also suspends its use of some resources to allow the ad to take advantage of them. For example, when you make the call to display an interstitial ad, be sure to pause any audio output being produced by your app. You can resume playing sounds in the `DidDismissScreen` method of `IInterstitialDelegate` interface or in the `ScreenDismissed` event handler, which will be invoked when the user has finished interacting with the ad. In addition, consider temporarily halting any intense computation tasks (such as a game loop) while the ad is being displayed. This will make sure the user doesn't experience slow or unresponsive graphics or stuttered video. - -### Allow for adequate loading time. - -Just as it's important to make sure you display interstitial ads at an appropriate time, it's also important to make sure the user doesn't have to wait for them to load. Loading the ad in advance by calling `LoadRequest` method before you intend to call `PresentFromRootViewController` can ensure that your app has a fully loaded interstitial ad at the ready when the time comes to display one. - -### Don't flood the user with ads. - -While increasing the frequency of interstitial ads in your app might seem like a great way to increase revenue, it can also degrade the user experience and lower clickthrough rates. Make sure that users aren't so frequently interrupted that they're no longer able to enjoy the use of your app. - -### Don't use the `InterstitialDelegate.DidReceiveAd` or `Interstitial.AdReceived` events to show the interstitial. - -This can cause a poor user experience. Instead, pre-load the ad before you need to show it. Then check the `IsReady` method on `Interstitial` to find out if it is ready to be shown. - ---- - -# Native Ads Advanced (Unified) - -> ![note_icon] _Native Ads Advanced is currently in a limited beta release. If you are interested in participating, reach out to your account manager._ - -Native ads are ad assets that are presented to users via UI components that are native to the platform. They're shown using the same classes you already use in your storyboards, and can be formatted to match your app's visual design. When an ad loads, your app receives an ad object that contains its assets, and the app (rather than the SDK) is then responsible for displaying them. - -This guide will show you how to use the Google Mobile Ads SDK to implement [native ads][6] in an iOS application, as well as some important things to consider along the way. - -## Loading ads - -There are two [system-defined formats for native ads][7]: app install and content. - -Both types of ads are represented by one class: `UnifiedNativeAd`. An instance of this class contains the assets for the native ad. Note that depending on the type of ad represented by the `UnifiedNativeAd`, some fields will not be populated (i.e., they will be `null`). - -Native ads are loaded via `AdLoader` objects, which send messages to their delegates according to the `IAdLoaderDelegate` interface. - -### Initialize the ad loader - -Before you can load an ad, you have to initialize the ad loader. The following code demonstrates how to initialize a `AdLoader`: - -```csharp -adLoader = new AdLoader ("ca-app-pub-3940256099942544/3986624511", - this, - new [] { AdLoaderType.UnifiedNative }, - new [] { /* ad loader options objects */ }) { - Delegate = this -}; -``` - -You'll need an ad unit ID (you can use the test ID), constants to pass in the `adTypes` array to specify which native formats you want to request, and any options you wish to set in the options parameter. The list of possible values for the `options` parameter can be found below in the Setting **native ad options** section below. - -The adTypes array should contain the following constant: - -* AdLoaderType.UnifiedNative - -### Implement the ad loader delegate - -The ad loader delegate needs to implement protocols specific your ad type. For unified native ads: - -* `IUnifiedNativeAdLoaderDelegate`: This protocol includes a message that's sent to the delegate when a unified native ad has loaded: - - ```csharp - public void DidReceiveUnifiedNativeAd (AdLoader adLoader, UnifiedNativeAd nativeAd); - ``` - -### Request the ad - -Once your `AdLoader` is initialized, call its `LoadRequest` method to request an ad: - -```csharp -adLoader.LoadRequest (Request.GetDefaultRequest ()); -``` - -The `LoadRequest` method in `AdLoader` accepts the same `Request` objects as banners and interstitials. You can use request objects to [add targeting information][8], just as you would with other ad types. - -### When to request ads - -Apps displaying native ads are free to request them in advance of when they'll actually be displayed. In many cases, this is the recommended practice. An app displaying a list of items with native ads mixed in, for example, can load native ads for the whole list, knowing that some will be shown only after the user scrolls the view and some may not be displayed at all. - -> ![note_icon] _While prefetching ads is a great technique, it's important that you don't keep old ads around forever without displaying them. Any native ad objects that have been held without display for longer than an hour should be discarded and replaced with new ads from a new request_ - -> ![note_icon] _**Note:**_ _When reusing a `AdLoader`, make sure you wait for each request to complete before calling `LoadRequest` again._ - -### Determining when loading has finished - -After an app calls `LoadRequest`, it can get the results of the request via calls to: - -* `DidFailToReceiveAd` in `IAdLoaderDelegate` -* `DidReceiveUnifiedNativeAd` in `IUnifiedNativeAdLoaderDelegate` - -A request for a single ad will result in one call to one of those methods. - -A request for multiple ads will result in at least one callback to the above methods, but no more than the maximum number of ads requested. - -> ![note_icon] _**Note:**_ _Requests for multiple native ads don't currently work for AdMob ad unit IDs that have been configured for mediation. Publishers using mediation should avoid using the `MultipleAdsAdLoaderOptions` class when making requests._ - -In addition, `IAdLoaderDelegate` offers the `DidFinishLoading` callback. This delegate method indicates that an ad loader has finished loading ads and no other ads or errors will be reported for the request. Here's an example of how to use it when loading several native ads at one time: - -```csharp -using Google.MobileAds - -public partial class ViewController : UIViewController, IUnifiedNativeAdLoaderDelegate, IVideoControllerDelegate { - AdLoader adLoader; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - - var multipleAdsOptions = new MultipleAdsAdLoaderOptions { NumberOfAds = 5 }; - adLoader = new AdLoader ("YOUR_AD_UNIT_ID", this, new [] { AdLoaderType.UnifiedNative }, new [] { multipleAdsOptions }) { - Delegate = this - }; - adLoader.LoadRequest (Request.GetDefaultRequest ()); - } - - public void DidReceiveUnifiedNativeAd (AdLoader adLoader, UnifiedNativeAd nativeAd) - { - // A unified native ad has loaded, and can be displayed. - } - - // @optional - (void)adLoaderDidFinishLoading:(GADAdLoader *)adLoader; - [Export ("adLoaderDidFinishLoading:")] - void DidFinishLoading (AdLoader adLoader) - { - // The adLoader has finished loading ads, and a new request can be sent. - } -} -``` - -### Handling failed requests - -The above protocols extend the `IAdLoaderDelegate` protocol, which defines a message sent when ads fail to load. You can use the `RequestError` object to determine the cause of the error. - -```csharp -public void DidFailToReceiveAd (AdLoader adLoader, RequestError error); -``` - -### Get notified of native ad events - -To be notified of events related to the native ad interactions, you can use the `IUnifiedNativeAdDelegate` interface methods by setting the `UnifiedNativeAd.Delegate` property or use the `UnifiedNativeAd` events but you cannot use both or create a mix of them: - -```csharp -// If you decide to implement the IUnifiedNativeAdDelegate interface -nativeAd.Delegate = this; -``` - -Then implement `IUnifiedNativeAdDelegate` interface or set the `UnifiedNativeAd` events to receive the following calls: - -```csharp -[Export ("nativeAdDidRecordImpression:")] -void DidRecordImpression (UnifiedNativeAd nativeAd) -{ - // The native ad was shown. -} - -nativeAd.ImpressionRecorded += (sender, e) => { - // The native ad was shown. -}; - -[Export ("nativeAdDidRecordClick:")] -void DidRecordClick (UnifiedNativeAd nativeAd) -{ - // The native ad was clicked on. -} - -nativeAd.ClickRecorded += (sender, e) => { - // The native ad was clicked on. -}; - -[Export ("nativeAdWillPresentScreen:")] -void WillPresentScreen (UnifiedNativeAd nativeAd) -{ - // The native ad will present a full screen view. -} - -nativeAd.WillPresentScreen += (sender, e) => { - // The native ad will present a full screen view. -}; - -// @optional -(void)nativeAdWillDismissScreen:(GADUnifiedNativeAd * _Nonnull)nativeAd; -void WillDismissScreen (UnifiedNativeAd nativeAd) -{ - // The native ad will dismiss a full screen view. -} - -nativeAd.WillDismissScreen += (sender, e) => { - // The native ad will dismiss a full screen view. -}; - -[Export ("nativeAdDidDismissScreen:")] -void DidDismissScreen (UnifiedNativeAd nativeAd) -{ - // The native ad did dismiss a full screen view. -} - -nativeAd.ScreenDismissed += (sender, e) => { - // The native ad did dismiss a full screen view. -}; - -[Export ("nativeAdWillLeaveApplication:")] -void WillLeaveApplication (UnifiedNativeAd nativeAd) -{ - // The native ad will cause the application to become inactive and - // open a new application. -} - -nativeAd.WillLeaveApplication += (sender, e) => { - // The native ad will cause the application to become inactive and - // open a new application. -}; -``` - -## Native ad options - -The last parameter included in the creation of the `AdLoader` above is an optional array of objects. - -```csharp -adLoader = new AdLoader ("ca-app-pub-3940256099942544/3986624511", - this, - new [] { AdLoaderType.UnifiedNative }, - --> new [] { /* ad loader options objects */ }); -``` - -This optional array holds one or more instances of a `AdLoaderOptions` subclass (`NativeAdImageAdLoaderOptions`), which are objects that an app can use to indicate its preferences for how native ads should be loaded and behave. - -`NativeAdImageAdLoaderOptions` contains properties relating to images in Native Advanced ads. Apps can control how a `AdLoader` handles Native Ads Advanced image assets by creating a `NativeAdImageAdLoaderOptions` object, setting its properties (`DisableImageLoading`, `PreferredImageOrientation`, and `HhouldRequestMultipleImages`), and passing it in during initialization. - -`NativeAdImageAdLoaderOptions` has the following propeties: - -* `DisableImageLoading` - - Image assets for native ads are returned via instances of `NativeAdImage`, which contains `Image` and `ImageUrl` properties. If `DisableImageLoading` is set to `false`, which is the default, the SDK will fetch image assets automatically and populate both the `Image` and the `ImageUrl` properties for you. If it's set to `true`, the SDK will only populate `ImageUrl`, allowing you to download the actual images at your discretion. - -* `PreferredImageOrientation` - - Some creatives have multiple images available to match different device orientations. Apps can request images for a particular orientation by setting this property to one of the orientation constants: - - * `NativeAdImageAdLoaderOptionsOrientation.Any` - * `NativeAdImageAdLoaderOptionsOrientation.Landscape` - * `NativeAdImageAdLoaderOptionsOrientation.Portrait` - - > ![note_icon] `If you use `PreferredImageOrientation` to specify a preference for landscape or portrait image orientation, the SDK will place images matching that orientation first in image asset arrays and place non-matching images after them. Since some ads will only have one orientation available, publishers should make sure that their apps can handle both landscape and portrait images.` - - If this property is not set, the default value of `NativeAdImageAdLoaderOptionsOrientation.Any` will be used. - -* `ShouldRequestMultipleImages` - - Some image assets will contain a series of images rather than just one. By setting this value to `true`, your app indicates that it's prepared to display all the images for any assets that have more than one. By setting it to `false` (the default) your app instructs the SDK to provide just the first image for any assets that contain a series. - - If no `AdLoaderOptions` objects are passed in when initializing a `AdLoader`, the default value for each option will be used. - -### `NativeAdViewOptions` - -`NativeAdViewAdOptions` objects are used to indicate preferences for how native ad views should represent ads. They have a single property: `PreferredAdChoicesPosition`, which you can use to specify the location where the AdChoices icon should be placed. The icon can appear at any corner of the ad, and defaults to `AdChoicesPosition.TopRightCorner`. The possible values for this property are: - -* AdChoicesPosition.TopRightCorner -* AdChoicesPosition.TopLeftCorner -* AdChoicesPosition.BottomRightCorner -* AdChoicesPosition.BottomLeftCorner - -Here's an example showing how to place the AdChoices icon in the top left corner of an ad: - -```csharp -NativeAdViewAdOptions adViewAdOptions = new NativeAdViewAdOptions { PreferredAdChoicesPosition = AdChoicesPosition.TopLeftCorner }; -adLoader = new AdLoader ("YOUR_AD_UNIT_ID", this, new [] { AdLoaderType.UnifiedNative }, new [] { adViewAdOptions }); -``` - -### `VideoOptions` - -`VideoOptions` objects are used to indicate how native video assets should be displayed. They offer a single property: `StartMuted`. - -This boolean indicates whether video assets should begin playback in a muted state. The default value is `true`. - -### `MultipleAdsAdLoaderOptions` - -`MultipleAdsAdLoaderOptions` objects allow publishers to instruct an ad loader to load multiple ads in a single request. Ads loaded in this way are guaranteed to be unique. `MultipleAdsAdLoaderOptions` has a single property, `NumberOfAds`, which represents the number of ads the ad loader should attempt to return for the request. By default this value is one, and it's capped at a maximum of five (even if an app requests more ads, at most five will be returned). The actual number of ads returned is not guaranteed, but will be between zero and `NumberOfAds`. - -## Displaying a system-defined native ad format - -When an ad loads, your app receives an ad object via one of the `IAdLoaderDelegate` protocol messages. Your app is then responsible for displaying the ad (though it doesn't necessarily have to do so immediately). To make displaying system-defined ad formats easier, the SDK offers some useful resources. - -### UnifiedNativeAdView - -For the `UnifiedNativeAd`, there is a corresponding "ad view" class: `UnifiedNativeAdView`. This ad view class is a `UIView` that publishers should use to display the ad. A single `UnifiedNativeAdView`, for example, can display a single instance of a `UnifiedNativeAd`. Each of the `UIView` objects used to display that ad's assets should be subviews of that `UnifiedNativeAdView` object. - -If you were displaying an app install ad in a `UITableView`, for example, the view hierarchy for one of the cells might look like this: - -![UITable](https://developers.google.com/admob/images/ios_app_install_layout.png) - -The `UnifiedNativeAdView` class also provides `IBOutlets` used to register the view used for each individual asset, and a method to register the `UnifiedNativeAd` object itself. Registering the views in this way allows the SDK to automatically handle tasks such as: - -* Recording clicks. -* Recording impressions (when the first pixel is visible on the screen). -* Displaying the AdChoices overlay. - -### The AdChoices overlay - -For indirect native ads (delivered via AdMob backfill or through Ad Exchange or AdSense), an AdChoices overlay is added by the SDK. Please, leave space in [your preferred corner](#NativeAdViewOptions) of your native ad view for the automatically inserted AdChoices logo. Also, it's important that the AdChoices overlay be easily seen, so choose background colors and images appropriately. For more information on the overlay's appearance and function, see [Guidelines for programmatic native ads using native styles][5]. - -### Ad attribution - -When displaying programmatic native ads, you must display an ad attribution to denote that the view is an advertisement. - -## Native video - -In addition to images, text, and numbers, some native ads contain video assets. Not every ad will have one and apps are not required to display videos when they're included with an ad. - -### MediaView - -Video assets are displayed to users via `MediaView`. This is a `UIView` that can be defined in a xib file or constructed dynamically. It should be placed within the view hierarchy of a `NativeAdView`, as with any other asset view. - -Unlike other asset views, however, apps do not need to manually populate a `MediaView` with its asset. The SDK handles this automatically as follows: - -* If a video asset is available, it is buffered and starts playing inside the MediaView. -* If the ad does not contain a video asset, the first image asset is downloaded and placed inside the `MediaView` instead. - -This autopopulation of the `MediaView` with an available image asset does not always work when you're using mediation. Because not all mediation adapters guarantee that they'll create a media view for every ad, it's possible for a blank one to be returned for mediated ads. If you're using mediation, you should check the `HasVideoContent` property of an ad's `VideoController` to see if it contains a video asset, before displaying the `MediaView`. If there is no video content, you should display an image view that you populate manually with a relevant image. - -### VideoController - -The `VideoController` class is used to retrieve information about video assets. `NativeAppInstallAd` and `NativeContentAd` both offer a `VideoController` property that exposes the `VideoController` for each ad: - -```csharp -VideoController vc1 = myAppInstallAd.VideoController; -VideoController vc2 = myContentAd.VideoController; -``` - -This property is never `null`, even when the ad doesn't contain a video asset. - -`VideoController` offers the following methods for querying video state: - -* HasVideoContent - True if the ad includes a video asset, false otherwise. -* AspectRatio - The aspect ratio of the video (width/height) or zero (if no video asset is present). - -Apps can also set a `IVideoControllerDelegate` for the `VideoController` to be notified of events in the lifecycle of a video asset, also, you can use `VideoController` events instead of `IVideoControllerDelegate` methods. `IVideoControllerDelegate` offers a single optional method, `DidEndVideoPlayback`, as well as `VideoController` offers a `VideoPlaybackEnded` event, which is sent when a video completes playback. - -Here's an example of `IViewControllerDelegate` in action: - -```csharp -public class YourViewController : UIViewController, IUnifiedNativeAdLoaderDelegate, IVideoControllerDelegate -{ - public override void ViewDidLoad () - { - base.ViewDidLoad (); - } - - public void DidReceiveUnifiedNativeAd (AdLoader adLoader, UnifiedNativeAd nativeAd) - { - nativeAppInstallAd.VideoController.Delegate = this; - } - - [Export ("videoControllerDidEndVideoPlayback:")] - public void DidEndVideoPlayback (VideoController videoController) - { - // Here apps can take action knowing video playback is finished. - // This is handy for things like unmuting audio, and so on. - } -} -``` - -Here's an example of `ViewController` events in action: - -```csharp -public class YourViewController : UIViewController, IUnifiedNativeAdLoaderDelegate -{ - public override void ViewDidLoad () - { - base.ViewDidLoad (); - nativeAppInstallAd.VideoController.VideoPlaybackEnded += (sender, e) => { - // Here apps can take action knowing video playback is finished. - // This is handy for things like unmuting audio, and so on. - }; - } - - public void DidReceiveUnifiedNativeAd (AdLoader adLoader, UnifiedNativeAd nativeAd) - { - - } -} -``` - ---- - -# Native Ads Advanced - -> ![note_icon] **_Note:_** _Native Ads Advanced is currently in a limited beta release. If you are interested in participating, reach out to your account manager to discuss the possibility. This feature will be made available to all publishers at the conclusion of the beta._ - -Native ads are ad assets that are presented to users via UI components that are native to the platform. They're shown using the same classes you already use in your storyboards, and can be formatted to match your app's visual design. When an ad loads, your app receives an ad object that contains its assets, and the app (rather than the SDK) is then responsible for displaying them. - -## Loading ads - -There are two [system-defined formats for native ads][4]: app install and content. - -App install ads are represented by `NativeAppInstallAd`, and content ads are represented by `NativeContentAd`. Instances of the classes contain the assets for the native ad. - -Native Advanced ads are loaded via `AdLoader` objects, which send messages to their delegates according to the `IAdLoaderDelegate` interface. - -### Initialize a AdLoader - -Before you can load an ad, you have to initialize the ad loader. The following code demonstrates how to initialize a `AdLoader` for an app install ad: - -```csharp -var adLoader = new AdLoader ("ca-app-pub-3940256099942544/3986624511", - this, - new NSObject [] { /* ad type constants */ }, - new AdLoaderOptions [] { /* ad loader options objects */ }); -adLoader.Delegate = this; -``` - -You'll need an ad unit ID (you can use the test ID), constants to pass in the `adTypes` array to specify which native formats you want to request, and any options you wish to set in the options parameter. The list of possible values for the `options` parameter can be found below in the Setting **native ad options** section below. - -The adTypes array should contain one or more of the following constants: - -* AdLoaderType.NativeAppInstall -* AdLoaderType.NativeContent - -### Implement the ad loader delegate - -The ad loader delegate needs to implement protocols specific your ad type. For native ads: - -* `INativeAppInstallAdLoaderDelegate`: This interface includes a message that's sent to the delegate when an app install ad has loaded: - - ```csharp - public void DidReceiveNativeAppInstallAd (AdLoader adLoader, NativeAppInstallAd nativeAppInstallAd); - ``` - -* `INativeContentAdLoaderDelegate` This protocol defines a message sent when a content ad has loaded: - - ```csharp - public void DidReceiveNativeContentAd (AdLoader adLoader, NativeContentAd nativeContentAd); - ``` - -### Request the ad - -Once your `AdLoader` is initialized, call its `LoadRequest` method to request an ad: - -```csharp -adLoader.LoadRequest (Request.GetDefaultRequest ()); -``` - -The `LoadRequest` method in `AdLoader` accepts the same `Request` objects as banners and interstitials. You can use request objects to add targeting information just as you would with other ad types. - -### When to request ads - -Apps displaying native ads are free to request them in advance of when they'll actually be displayed. In many cases, this is the recommended practice. An app displaying a list of items with native ads mixed in, for example, can load native ads for the whole list, knowing that some will be shown only after the user scrolls the view and some may not be displayed at all. - -> ![note_icon] _While prefetching ads is a great technique, it's important that you don't keep old ads around forever without displaying them. Any native ad objects that have been held without display for longer than an hour should be discarded and replaced with new ads from a new request._ - -> ![note_icon] **_Note:_** _When reusing a `AdLoader`, make sure you wait for each request to complete before calling `LoadRequest` again._ - -### Determining when loading has finished - -After an app calls `LoadRequest`, it can get the results of the request via calls to: - -* `DidFailToReceiveAd` in `IAdLoaderDelegate` -* `DidReceiveNativeAppInstallAd` in `INativeAppInstallAdLoaderDelegate` -* `DidReceiveNativeContentAd` in `INativeContentAdLoaderDelegate` - -A request for a single ad will result in one call to one of those methods. - -A request for multiple ads will result in at least one callback to the above methods, but no more than the maximum number of ads requested. - -> ![note_icon] _**Note:**_ _Requests for multiple native ads don't currently work for AdMob ad unit IDs that have been configured for mediation. Publishers using mediation should avoid using the `MultipleAdsAdLoaderOptions` class when making requests._ - -In addition, `IAdLoaderDelegate` offers the `DidFinishLoading` callback. This delegate method indicates that an ad loader has finished loading ads and no other ads or errors will be reported for the request. Here's an example of how to use it when loading several native ads at one time: - -```csharp -using Google.MobileAds - -public partial class ViewController : UIViewController, INativeAppInstallAdLoaderDelegate, INativeContentAdLoaderDelegate, IVideoControllerDelegate { - AdLoader adLoader; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - - var multipleAdsOptions = new MultipleAdsAdLoaderOptions { NumberOfAds = 5 }; - adLoader = new AdLoader ("YOUR_AD_UNIT_ID", this, new [] { AdLoaderType.UnifiedNative }, new [] { multipleAdsOptions }) { - Delegate = this - }; - adLoader.LoadRequest (Request.GetDefaultRequest ()); - } - - public void DidReceiveNativeAppInstallAd (AdLoader adLoader, NativeAppInstallAd nativeAppInstallAd) - { - // An app install ad has loaded, and can be displayed. - } - - public void DidReceiveNativeContentAd (AdLoader adLoader, NativeContentAd nativeContentAd) - { - // A content ad has loaded, and can be displayed. - } - - // @optional - (void)adLoaderDidFinishLoading:(GADAdLoader *)adLoader; - [Export ("adLoaderDidFinishLoading:")] - void DidFinishLoading (AdLoader adLoader) - { - // The adLoader has finished loading ads, and a new request can be sent. - } -} -``` - -### Handling failed requests - -The above protocols extend the `IAdLoaderDelegate` protocol, which defines a message sent when ads fail to load. You can use the `RequestError` object to determine the cause of the error. - -```csharp -public void DidFailToReceiveAd (AdLoader adLoader, RequestError error); -``` - -### Get notified of native ad events - -To be notified of events related to the native ad interactions, you can use the `IUnifiedNativeAdDelegate` interface methods by setting the `UnifiedNativeAd.Delegate` property or use the `UnifiedNativeAd` events but you cannot use both or create a mix of them: - -```csharp -// If you decide to implement the IUnifiedNativeAdDelegate interface -nativeAd.Delegate = this; -``` - -Then implement `IUnifiedNativeAdDelegate` interface or set the `UnifiedNativeAd` events to receive the following calls: - -```csharp -[Export ("nativeAdDidRecordImpression:")] -void DidRecordImpression (UnifiedNativeAd nativeAd) -{ - // The native ad was shown. -} - -nativeAd.ImpressionRecorded += (sender, e) => { - // The native ad was shown. -}; - -[Export ("nativeAdDidRecordClick:")] -void DidRecordClick (UnifiedNativeAd nativeAd) -{ - // The native ad was clicked on. -} - -nativeAd.ClickRecorded += (sender, e) => { - // The native ad was clicked on. -}; - -[Export ("nativeAdWillPresentScreen:")] -void WillPresentScreen (UnifiedNativeAd nativeAd) -{ - // The native ad will present a full screen view. -} - -nativeAd.WillPresentScreen += (sender, e) => { - // The native ad will present a full screen view. -}; - -// @optional -(void)nativeAdWillDismissScreen:(GADUnifiedNativeAd * _Nonnull)nativeAd; -void WillDismissScreen (UnifiedNativeAd nativeAd) -{ - // The native ad will dismiss a full screen view. -} - -nativeAd.WillDismissScreen += (sender, e) => { - // The native ad will dismiss a full screen view. -}; - -[Export ("nativeAdDidDismissScreen:")] -void DidDismissScreen (UnifiedNativeAd nativeAd) -{ - // The native ad did dismiss a full screen view. -} - -nativeAd.ScreenDismissed += (sender, e) => { - // The native ad did dismiss a full screen view. -}; - -[Export ("nativeAdWillLeaveApplication:")] -void WillLeaveApplication (UnifiedNativeAd nativeAd) -{ - // The native ad will cause the application to become inactive and - // open a new application. -} - -nativeAd.WillLeaveApplication += (sender, e) => { - // The native ad will cause the application to become inactive and - // open a new application. -}; -``` - -## Native ad options - -The last parameter included in the creation of the `AdLoader` above is an optional array of objects: - -```csharp -var adLoader = new AdLoader ("ca-app-pub-3940256099942544/3986624511", - this, - new NSObject [] { /* ad type constants */ }, - --> new AdLoaderOptions [] { /* ad loader options objects */ }); -``` - -This optional array holds one or more instances of a `AdLoaderOptions` subclass, objects that an app can use to indicate its preferences for how native ads should be loaded and behave. - -`NativeAdImageAdLoaderOptions` contains properties relating to images in Native Advanced ads. Apps can control how a `AdLoader` handles Native Ads Advanced image assets by creating a `NativeAdImageAdLoaderOptions` object, setting its properties (DisableImageLoading, PreferredImageOrientation, and ShouldRequestMultipleImages), and passing it in during initialization. - -* `DisableImageLoading` - - Image assets for native ads are returned via instances of `NativeAdImage`, which contains `Image` and `ImageUrl` properties. If `DisableImageLoading` is set to `false`, which is the default, the SDK will fetch image assets automatically and populate both the `Image` and the `ImageUrl` properties for you. If it's set to `true`, the SDK will only populate `ImageUrl`, allowing you to download the actual images at your discretion. - -* `PreferredImageOrientation` - - Some creatives have multiple images available to match different device orientations. Apps can request images for a particular orientation by setting this property to one of the orientation constants: - - * `NativeAdImageAdLoaderOptionsOrientation.Any` - * `NativeAdImageAdLoaderOptionsOrientation.Landscape` - * `NativeAdImageAdLoaderOptionsOrientation.Portrait` - - > ![note_icon] `If you use `PreferredImageOrientation` to specify a preference for landscape or portrait image orientation, the SDK will place images matching that orientation first in image asset arrays and place non-matching images after them. Since some ads will only have one orientation available, publishers should make sure that their apps can handle both landscape and portrait images.` - - If this property is not set, the default value of `NativeAdImageAdLoaderOptionsOrientation.Any` will be used. - -* `ShouldRequestMultipleImages` - - Some image assets will contain a series of images rather than just one. By setting this value to `true`, your app indicates that it's prepared to display all the images for any assets that have more than one. By setting it to `false` (the default) your app instructs the SDK to provide just the first image for any assets that contain a series. - - If no `AdLoaderOptions` objects are passed in when initializing a `AdLoader`, the default value for each option will be used. - -### `NativeAdViewOptions` - -`NativeAdViewAdOptions` objects are used to indicate preferences for how native ad views should represent ads. They have a single property: `PreferredAdChoicesPosition`, which you can use to specify the location where the AdChoices icon should be placed. The icon can appear at any corner of the ad, and defaults to `AdChoicesPosition.TopRightCorner`. The possible values for this property are: - -* AdChoicesPosition.TopRightCorner -* AdChoicesPosition.TopLeftCorner -* AdChoicesPosition.BottomRightCorner -* AdChoicesPosition.BottomLeftCorner - -Here's an example showing how to place the AdChoices icon in the top left corner of an ad: - -```csharp -NativeAdViewAdOptions adViewAdOptions = new NativeAdViewAdOptions { PreferredAdChoicesPosition = AdChoicesPosition.TopLeftCorner }; -adLoader = new AdLoader ("YOUR_AD_UNIT_ID", this, new [] { AdLoaderType.UnifiedNative }, new [] { adViewAdOptions }); -``` - -### `VideoOptions` - -`VideoOptions` objects are used to indicate how native video assets should be displayed. They offer a single property: `StartMuted`. - -This boolean indicates whether video assets should begin playback in a muted state. The default value is `true`. - -### `MultipleAdsAdLoaderOptions` - -`MultipleAdsAdLoaderOptions` objects allow publishers to instruct an ad loader to load multiple ads in a single request. Ads loaded in this way are guaranteed to be unique. `MultipleAdsAdLoaderOptions` has a single property, `NumberOfAds`, which represents the number of ads the ad loader should attempt to return for the request. By default this value is one, and it's capped at a maximum of five (even if an app requests more ads, at most five will be returned). The actual number of ads returned is not guaranteed, but will be between zero and `NumberOfAds`. - -## Displaying a system-defined native ad format - -When an ad loads, your app receives an ad object via one of the `IAdLoaderDelegate` protocol messages. Your app is then responsible for displaying the ad (though it doesn't necessarily have to do so immediately). To make displaying system-defined ad formats easier, the SDK offers some useful resources. - -### The ad view classes - -For each of the system-defined formats, there is a corresponding "ad view" class: `NativeAppInstallAdView` for app install ads, and `NativeContentAdView` for content ads. These ad view classes are `UIView`s that publishers should use to display ads of the corresponding format. A single `NativeAppInstallAdView`, for example, can display a single instance of a `NativeAppInstallAd`. Each of the `UIView`s used to display that ad's assets should be children of that `NativeAppInstallAdView` object. - -If you were displaying an app install ad in a `UITableView`, for example, the view hierarchy for one of the cells might look like this: - -![UITable](https://developers.google.com/admob/images/ios_app_install_layout.png) - -The ad view classes also provide `Outlet` attributes used to register the view used for each individual asset, and a method to register the `NativeAd` object itself. Registering the views in this way allows the SDK to automatically handle tasks such as: - -* Recording clicks. -* Recording impressions (when the first pixel is visible on the screen). -* Displaying the AdChoices overlay. - -### The AdChoices overlay - -An AdChoices overlay is added to each ad view by the SDK. Leave space in [your preferred corner](#NativeAdViewOptions) of your native ad view for the automatically inserted AdChoices logo. Also, it's important that the AdChoices overlay be easily seen, so choose background colors and images appropriately. For more information on the overlay's appearance and function, see [Guidelines for programmatic native ads using native styles][5]. - -### Ad attribution - -When displaying programmatic native ads, you must display an ad attribution to denote that the view is an advertisement. - -## Native video - -In addition to images, text, and numbers, some native ads contain video assets. Not every ad will have one and apps are not required to display videos when they're included with an ad. - -### MediaView - -Video assets are displayed to users via `MediaView`. This is a `UIView` that can be defined in a xib file or constructed dynamically. It should be placed within the view hierarchy of a `NativeAdView`, as with any other asset view. - -Unlike other asset views, however, apps do not need to manually populate a `MediaView` with its asset. The SDK handles this automatically as follows: - -* If a video asset is available, it is buffered and starts playing inside the MediaView. -* If the ad does not contain a video asset, the first image asset is downloaded and placed inside the `MediaView` instead. - -This autopopulation of the `MediaView` with an available image asset does not always work when you're using mediation. Because not all mediation adapters guarantee that they'll create a media view for every ad, it's possible for a blank one to be returned for mediated ads. If you're using mediation, you should check the `HasVideoContent` property of an ad's `VideoController` to see if it contains a video asset, before displaying the `MediaView`. If there is no video content, you should display an image view that you populate manually with a relevant image. - -### VideoController - -The `VideoController` class is used to retrieve information about video assets. `NativeAppInstallAd` and `NativeContentAd` both offer a `VideoController` property that exposes the `VideoController` for each ad: - -```csharp -VideoController vc1 = myAppInstallAd.VideoController; -VideoController vc2 = myContentAd.VideoController; -``` - -This property is never `null`, even when the ad doesn't contain a video asset. - -`VideoController` offers the following methods for querying video state: - -* HasVideoContent - True if the ad includes a video asset, false otherwise. -* AspectRatio - The aspect ratio of the video (width/height) or zero (if no video asset is present). - -Apps can also set a `IVideoControllerDelegate` for the `VideoController` to be notified of events in the lifecycle of a video asset, also, you can use `VideoController` events instead of `IVideoControllerDelegate` methods. `IVideoControllerDelegate` offers a single optional method, `DidEndVideoPlayback`, as well as `VideoController` offers a `VideoPlaybackEnded` event, which is sent when a video completes playback. - -Here's an example of `IViewControllerDelegate` in action: - -```csharp -public class YourViewController : UIViewController, IVideoControllerDelegate -{ - public override void ViewDidLoad () - { - base.ViewDidLoad (); - nativeAppInstallAd.VideoController.Delegate = this; - } - - [Export ("videoControllerDidEndVideoPlayback:")] - public void DidEndVideoPlayback (VideoController videoController) - { - // Here apps can take action knowing video playback is finished. - // This is handy for things like unmuting audio, and so on. - } -} -``` - -Here's an example of `ViewController` events in action: - -```csharp -public class YourViewController : UIViewController -{ - public override void ViewDidLoad () - { - base.ViewDidLoad (); - nativeAppInstallAd.VideoController.VideoPlaybackEnded += (sender, e) => { - // Here apps can take action knowing video playback is finished. - // This is handy for things like unmuting audio, and so on. - }; - } -} -``` - ---- - -# Rewarded Video Ads - -Rewarded video ads are full-screen video ads that users have the option of watching in full in exchange for in-app rewards. - -This guide shows you how to integrate rewarded video ads from AdMob into an iOS app. - -## Request rewarded video - -`RewardBasedVideoAd` has a singleton design, so the following example shows a request to load an ad being made to the shared instance: - -```csharp -RewardBasedVideoAd.SharedInstance.LoadRequest (Request.GetDefaultRequest (), "ca-app-pub-3940256099942544/1712485313"); -``` - -To allow videos to be preloaded, we recommend calling `LoadRequest` method as early as possible (for example, in your app delegate's `FinishedLaunching` method). - -## Set up event notifications - -To set up event notification, you can use `RewardBasedVideoAd` events or implement the `IRewardBasedVideoAdDelegate` interface. - -If you plan to implement the `RewardBasedVideoAd` events, you are required to set the events prior to loading an ad. If you plan to implement `IRewardBasedVideoAdDelegate` interface instead of `RewardBasedVideoAd` events, you are required to set the `Delegate` prior to loading an ad. Insert the line shown before your `LoadRequest` call: - -```csharp -RewardBasedVideoAd.SharedInstance.Delegate = this; -``` - -`IRewardBasedVideoAdDelegate` notifies you of rewarded video lifecycle events. You are required to set the delegate prior to loading an ad. The most important method in this interface is `DidRewardUser` or `UserRewarded` if you are using `RewardBasedVideoAd` events, which is called when the user should be rewarded for watching a video. You may optionally implement other methods or events. - -Here is an example that logs each method available in `IRewardBasedVideoAdDelegate` interface, as well as each event in `RewardBasedVideoAd` class: - -```csharp -// For Export attribute -using Foundation; - -public void DidRewardUser (RewardBasedVideoAd rewardBasedVideoAd, AdReward reward) -{ - Console.WriteLine ($"Reward received with currency {reward.Type}, amount {reward.Amount}"); -} - -RewardBasedVideoAd.SharedInstance.UserRewarded += (sender, e) => { - Console.WriteLine ($"Reward received with currency {e.Reward.Type}, amount {e.Reward.Amount}"); -}; - -/// - -[Export ("rewardBasedVideoAd:didFailToLoadWithError:")] -public void DidFailToLoad (RewardBasedVideoAd rewardBasedVideoAd, NSError error) -{ - Console.WriteLine ($"Reward based video ad failed to load with error: {error.LocalizedDescription}."); -} - -RewardBasedVideoAd.SharedInstance.FailedToLoad += (sender, e) => { - Console.WriteLine ($"Reward based video ad failed to load with error: {e.Error.LocalizedDescription}."); -}; - -/// - -[Export ("rewardBasedVideoAdDidReceiveAd:")] -public void DidReceiveAd (RewardBasedVideoAd rewardBasedVideoAd) -{ - Console.WriteLine ("Reward based video ad is received."); -} - -RewardBasedVideoAd.SharedInstance.AdReceived += (sender, e) => { - Console.WriteLine ("Reward based video ad is received."); -}; - -/// - -[Export ("rewardBasedVideoAdDidOpen:")] -public void DidOpen (RewardBasedVideoAd rewardBasedVideoAd) -{ - Console.WriteLine ("Opened reward based video ad."); -} - -RewardBasedVideoAd.SharedInstance.Opened += (sender, e) => { - Console.WriteLine ("Opened reward based video ad."); -}; - -/// - -[Export ("rewardBasedVideoAdDidStartPlaying:")] -public void DidStartPlaying (RewardBasedVideoAd rewardBasedVideoAd) -{ - Console.WriteLine ("Reward based video ad started playing."); -} - -RewardBasedVideoAd.SharedInstance.PlayingStarted += (sender, e) => { - Console.WriteLine ("Reward based video ad started playing."); -}; - -/// - -[Export ("rewardBasedVideoAdDidClose:")] -public void DidClose (RewardBasedVideoAd rewardBasedVideoAd) -{ - Console.WriteLine ("Reward based video ad is closed."); -} - -RewardBasedVideoAd.SharedInstance.Closed += (sender, e) => { - Console.WriteLine ("Reward based video ad is closed."); -}; - -/// - -[Export ("rewardBasedVideoAdWillLeaveApplication:")] -public void WillLeaveApplication (RewardBasedVideoAd rewardBasedVideoAd) -{ - Console.WriteLine ("Reward based video ad will leave application."); -} - -RewardBasedVideoAd.SharedInstance.WillLeaveApplication += (sender, e) => { - Console.WriteLine ("Reward based video ad will leave application."); -}; -``` - -## Display rewarded video - -It is a best practice to ensure a rewarded video ad has completed loading before attempting to display it. The `IsReady` property indicates that a rewarded video ad request has been successfully fulfilled: - -```csharp -if (RewardBasedVideoAd.SharedInstance.IsReady) { - RewardBasedVideoAd.SharedInstance.PresentFromRootViewController (this); -} -``` - -## Reload a rewarded video - -A handy place to load a new rewarded video ad after the previous one is in `DidClose` interface method or `Closed` event: - -```csharp -[Export ("rewardBasedVideoAdDidClose:")] -public void DidClose (RewardBasedVideoAd rewardBasedVideoAd) -{ - RewardBasedVideoAd.SharedInstance.LoadRequest (Request.GetDefaultRequest (), "ca-app-pub-3940256099942544/1712485313"); -} - -RewardBasedVideoAd.SharedInstance.Closed += (sender, e) => { - RewardBasedVideoAd.SharedInstance.LoadRequest (Request.GetDefaultRequest (), "ca-app-pub-3940256099942544/1712485313"); -}; -``` - ---- - - # Targeting - -This guide explains how to provide targeting information to an ad request. - -## Request - -The `Request` object collects targeting information to be sent with an ad request. - -### Location - -If a user has granted your app location permissions, location data is automatically passed to the SDK. The SDK uses this data to improve ad targeting without requiring any code changes in your app. You can, of course, [enable or disable location data for ads][9]. - -Autopopulated location information is not forwarded to mediation networks and it may also be disabled entirely. Therefore, the SDK provides the ability to set location manually. - -After [getting the user's location][10], you can specify location-targeting information in the `Request` as follows: - -```csharp -var request = Request.GetDefaultRequest (); - -if (locationManager.Location != null) { - var currentLocation = locationManager.Location; - request.SetLocation ((nfloat)currentLocation.Coordinate.Latitude, (nfloat)currentLocation.Coordinate.Longitude, (nfloat)currentLocation.HorizontalAccuracy); -} -``` - -Out of respect for user privacy, Google asks that you only specify location if that information is already used by your app. - -### Child-directed setting - -For purposes of the Children's Online Privacy Protection Act (COPPA), there is a method called `Tag`. - -As an app developer, you can indicate whether you want Google to treat your content as child-directed when you make an ad request. When you indicate that you want Google to treat your content as child-directed, we take steps to disable IBA and remarketing ads on that ad request. The setting options are as follows: - -* Set `Tag` to `true` to indicates that you want your content treated as child-directed for purposes of COPPA. -* Set `Tag` to `false` to indicate that you don't want your content treated as child-directed for purposes of COPPA. -* Do not set `Tag` if you do not wish to indicate how you would like your content treated with respect to COPPA. - -```csharp -var request = Request.GetDefaultRequest (); -request.Tag (true); -``` - -By setting this tag, you certify that this notification is accurate and you are authorized to act on behalf of the owner of the app. You understand that abuse of this setting may result in termination of your Google account. - -### Users under the age of consent - -You can mark your ad requests to receive treatment for users in the European Economic Area (EEA) under the age of consent. This feature is designed to help facilitate compliance with the[ General Data Protection Regulation (GDPR)][11]. Note that you may have other legal obligations under GDPR. Please review the European Union’s guidance and consult with your own legal counsel. Please remember that Google's tools are designed to facilitate compliance and do not relieve any particular publisher of its obligations under the law. [Learn more about how the GDPR affects publishers][12]. - -When using this feature, a Tag For Users under the Age of Consent in Europe (TFUA) parameter will be included in the ad request. This parameter disables personalized advertising, including remarketing, for that specific ad request. It also disables requests to third-party ad vendors, such as ad measurement pixels and third-party ad servers. - -The setting can be used with all versions of the Google Mobile Ads SDK by using the `tag_for_under_age_of_consent` network extra. - -* Set `tag_for_under_age_of_consent` to `true` to indicate that you want the ad request to be handled in a manner suitable for users under the age of consent. -* Not setting `tag_for_under_age_of_consent` indicates that you don't want the ad request to be handled in a manner suitable for users under the age of consent. - -The following example indicates that you want TFUA included in your ad request: - -```csharp -var data = new Dictionary () { { "tag_for_under_age_of_consent", true } }; - -var request = Request.GetDefaultRequest (); -var extras = new Extras (); -extras.AdditionalParameters = NSDictionary.FromObjectsAndKeys (data.Values.ToArray (), data.Keys.ToArray (), data.Keys.Count); -request.RegisterAdNetworkExtras (extras); -``` - -> ![note_icon] _**Note:**_ _This `tag_for_under_age_of_consent` parameter is currently NOT forwarded to ad network mediation adapters. It is your responsibility to ensure that each third-party ad network in your application serves ads that are appropriate for users under the age of consent per GDPR._ - -### Ad content filtering - -Apps can set a maximum ad content rating for their ad requests using the max_ad_content_rating network extra. AdMob ads returned for these requests will have a content rating at or below that level. The possible values for this network extra are based on [digital content label classifications][13], and should be one of the following strings: - -* G -* PG -* T -* MA - -The following code configures an `Request` object to specify that ad content returned should correspond to a Digital Content Label designation no higher than G. - -```csharp -var data = new Dictionary () { { "max_ad_content_rating", "G" } }; - -var request = Request.GetDefaultRequest (); -var extras = new Extras (); -extras.AdditionalParameters = NSDictionary.FromObjectsAndKeys (data.Values.ToArray (), data.Keys.ToArray (), data.Keys.Count); -request.RegisterAdNetworkExtras (extras); -``` - -### Content URL - -When requesting an ad, apps may pass the URL of the content they are serving. This enables keyword targeting to match the ad with the content. - -For example, if your app serves blog articles and is requesting an ad while showing content from the article http://googleadsdeveloper.blogspot.com/2016/03/rewarded-video-support-for-admob.html, then you can pass this URL to target relevant keywords: - -```csharp -var request = Request.GetDefaultRequest (); -request.ContentUrl = "http://googleadsdeveloper.blogspot.com/2016/03/rewarded-video-support-for-admob.html"; -``` - -## Load an ad with targeting - -Once all of your request targeting information is set, call `LoadRequest` on `BannerView` with your `Request` instance. - -```csharp -var request = Request.GetDefaultRequest (); -request.Tag (true); -request.ContentUrl = "http://googleadsdeveloper.blogspot.com/2016/03/rewarded-video-support-for-admob.html"; -adView.LoadRequest (request); -``` - -## FAQ - -* **Can I release my app with `Request.TestDevices`?** - * Yes. Test ads are only shown on specific devices that you specify, so all of your users will still receive production ads. - -* **What targeting gets used when an ad automatically refreshes?** - * On ad refresh, the previously specified `Request` object is used for targeting again. To set new targeting, explicitly call `LoadRequest` on `BannerView` with a new `Request` object. - ---- - -# Reporting - -To learn more about this, please, read the following [documentation][14]. - ---- - -# Global Settings - -The `MobileAds` class provides global settings for controlling certain information collected by the Mobile Ads SDK. - -## Video ad volume control - -If your app has its own volume controls (such as custom music or sound effect volumes), disclosing app volume to the Google Mobile Ads SDK allows video ads to respect app volume settings. This ensures users receive video ads with the expected audio volume. - -The device volume, controlled through volume buttons or OS-level volume slider, determines the volume for device audio output. However, apps can independently adjust volume levels relative to the device volume to tailor the audio experience. You can report the relative app volume to the Google Mobile Ads SDK by setting the `ApplicationVolume` property. Valid ad volume values range from 0.0 (silent) to 1.0 (current device volume). Here's an example of how to report the relative app volume to the SDK: - -```csharp -// Set app volume to be half of the current device volume. -MobileAds.SharedInstance.ApplicationVolume = 0.5f; -``` - -To inform the Google Mobile Ads SDK that the app volume has been muted, set the `ApplicationMuted` property, as shown below: - -```csharp -MobileAds.SharedInstance.ApplicationMuted = true; -``` - -Unmuting the app volume reverts it to its previously set level. By default, the app volume for the Google Mobile Ads SDK is set to 1 (the current device volume). - -> ![note_icon] _**Note:**_ _Video ads that are ineligible to be shown with muted audio are not returned for ad requests made when the app volume is reported as muted or set to a value of 0. This may restrict a subset of the broader video ads pool from serving._ - -## Changing audio session - -Audio sessions allow you to express to the system your intentions for your app's audio behavior. Additional information on audio sessions can be found in Apple's [Audio Session Programming Guide][15]. The available options for managing the Google Mobile Ads SDK audio is via the `AudioVideoManager` property. - -If you don't use audio in your app, you don't need to use these APIs. The Google Mobile Ads SDK will automatically manage the audio session category when it plays audio. If you do play audio in your app and you want tighter control of how and when Google Mobile Ads SDK plays audio, these APIs can help. - -On the audio video manager, you can set the `AudioSessionIsApplicationManaged` property to `true` if you want to take responsibility for managing the audio session category yourself. - -If you will manage the audio session category, you should implement `IAudioVideoManagerDelegate` and set the `Delegate` property on the audio video manager or use audio video manager to be notified of ads video and audio playback events. You should then change the audio session category to the relevant category as per Apple's Audio Session Programming Guide linked above. - -> ![note_icon] **_Note:_** _By default, the Mobile Ads SDK will set the audio session category to AVAudioSessionCategoryAmbient when playing ads muted. If you prefer to have your app use `AVAudioSessionCategoryOptionDuckOthers` in this scenario, you must implement the `IAudioVideoManagerDelegate` interface and set the audio video manager `AudioSessionIsApplicationManaged` to `true`._ - -Here is a simplified code sample which shows the recommended approach if your app plays music, using above APIs: - -```csharp -void SetUp () -{ - // If you decide to implement IAudioVideoManagerDelegate interface - MobileAds.SharedInstance.AudioVideoManager.Delegate = this; - - // If you decide to use events - MobileAds.SharedInstance.AudioVideoManager.WillPlayAudio += (sender, e) => { - // The mobile ads SDK is notifying your app that it will play audio. You - // could optionally pause music depending on your apps design. - MyAppObject.SharedInstance.PauseAllMusic (); - }; - - MobileAds.SharedInstance.AudioVideoManager.PlayingAudioStopped += (sender, e) => { - // The mobile ads SDK is notifying your app that it has stopped playing - // audio. Depending on your design, you could resume music here. - MyAppObject.SharedInstance.ResumeAllMusic (); - }; - - MobileAds.SharedInstance.AudioVideoManager.AudioSessionIsApplicationManaged = true; -} - -void MyAppWillStartPlayingMusic () -{ - // Mutes all Google video ads. - MobileAds.SharedInstance.AudioVideoManager.AudioSessionIsApplicationManaged = true; - MobileAds.SharedInstance.ApplicationMuted = true; -} - -void MyAppDidStopPlayingMusic () -{ - // Un-mutes all of our video ads. - MobileAds.SharedInstance.AudioVideoManager.AudioSessionIsApplicationManaged = false; - MobileAds.SharedInstance.ApplicationMuted = false; -} - -// If you decide to implement IAudioVideoManagerDelegate interface -#region AudioVideoManager Delegate - -[Export ("audioVideoManagerWillPlayAudio:")] -public void WillPlayAudio (AudioVideoManager audioVideoManager) -{ - // The mobile ads SDK is notifying your app that it will play audio. You - // could optionally pause music depending on your apps design. - MyAppObject.SharedInstance.PauseAllMusic (); -} - -[Export ("audioVideoManagerDidStopPlayingAudio:")] -public void DidStopPlayingAudio (AudioVideoManager audioVideoManager) -{ - // The mobile ads SDK is notifying your app that it has stopped playing - // audio. Depending on your design, you could resume music here. - MyAppObject.SharedInstance.ResumeAllMusic (); -} - -#endregion -``` - -## In-app purchase reporting - -To help grow your in-app purchase revenue and maximize the total revenue generated by your app, the Mobile Ads SDK now automatically collects general in-app purchase (IAP) information (such as item purchase price and currency). Now, you won't have to implement extra logic to track IAP conversions yourself. If you're an AdMob developer, we recommend that you leverage this new functionality to enjoy the benefits of AdMob's smart monetization offerings. This IAP reporting setting must always be enabled if you are running in-app purchase house ads (currently in limited beta). This is necessary for IAP house ad conversions to be reported. - -In our latest SDK release, in-app purchase reporting is enabled by default. If you'd like, however, you can disable it by using the `DisableAutomatedInAppPurchaseReporting` method (unless you are running IAP house ads, as noted above). The best moment to call this method is when the app launches: - -```csharp -public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) -{ - ... - - MobileAds.DisableAutomatedInAppPurchaseReporting (); - - return true; -} -``` - -## Crash reporting - -The Mobile Ads SDK inspects exceptions that occur in an iOS app and records them if they are caused by the SDK. These exceptions are collected so we can prevent them in future SDK versions. - -In our latest SDK release, crash reporting is enabled by default. If you don't want SDK-related exceptions to be recorded, you can disable this feature by calling the `DisableSDKCrashReporting` method. The best place to call this method is when the app launches: - -```csharp -public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) -{ - ... - - MobileAds.DisableSDKCrashReporting (); - - return true; -} -``` - ---- - -# Requesting Consent from European Users - -Under the Google [EU User Consent Policy][16], you must make certain disclosures to your users in the European Economic Area (EEA) and obtain their consent to use cookies or other local storage, where legally required, and to use personal data (such as AdID) to serve ads. This policy reflects the requirements of the EU ePrivacy Directive and the General Data Protection Regulation (GDPR). - -To support publishers in meeting their duties under this policy, Google offers a Consent SDK. The Consent SDK is an open-source library that provides utility functions for collecting consent from your users. - -Ads served by Google can be categorized as personalized or non-personalized, both requiring consent from users in the EEA. By default, ad requests to Google serve personalized ads, with ad selection based on the user's previously collected data. Google also supports configuring ad requests to serve non-personalized ads. [Learn more about personalized and non-personalized ads][17]. - -This guide describes how to use the Consent SDK to obtain consent from users. It also describes how to forward consent to the Google Mobile Ads SDK once you have obtained consent. - -## Tips for using the Consent SDK - -Prior to using any other methods in the Consent SDK, you should [update consent status](#update-consent-status) to make sure the Consent SDK has the latest information regarding the ad technology providers you've selected in the AdMob UI. If the list of ad technology providers has changed since the user last provided consent, the consent state is set back to an unknown state. - -### If you select 12 or fewer ad technology providers and don't use mediation - -You can use the Consent SDK to present a [Google-rendered consent form](#google-rendered-consent-form) to your users. The consent form displays a list of the ad technology providers you've selected in the AdMob UI. The Consent SDK stores the user consent response. - -If a user has consented to receive only non-personalized ads, you'll need to [forward consent to the Google Mobile Ads SDK](#forward-consent-to-the-google-mobile-ads-sdk). - -### If you select more than 12 ad technology providers and don't use mediation - -You can use the Consent SDK to dynamically retrieve the full list of ad technology providers from AdMob, as explained in [publisher-managed consent collection](#publisher-managed-consent-collection). However, you'll need to determine how the list of providers should be made available to your users and present your own consent form to your users. - -Once the user has made a consent choice, you can ask the Consent SDK to store the user's consent choice as explained in [Storing publisher managed consent](#storing-publisher-managed-consent). - -If a user has consented to receive only non-personalized ads, you'll need to [forward consent to the Google Mobile Ads SDK](#forward-consent-to-the-google-mobile-ads-sdk). - -### If you use AdMob mediation - -You can use the Consent SDK to dynamically retrieve the full list of ad technology providers from AdMob, as explained in [publisher-managed consent collection](#publisher-managed-consent-collection). You'll need to determine which additional ad technology providers from other ad networks need to be presented to your users for consent. - -As an app developer, you'll need to collect user consent for both the ad technology providers returned by the Consent SDK and the providers from other ad networks. You'll also need to manually store user consent responses and [forward consent to the Google Mobile Ads SDK](#forward-consent-to-the-google-mobile-ads-sdk) if the user consented to receive only non-personalized ads. - -> ![warning_icon] _**Warning:**_ _We recommend **against** using the Consent SDK to store publisher-managed consent if you collect consent for additional ad technology providers beyond those returned by the Consent SDK. The Consent SDK only tracks changes to the list of ad technology providers from AdMob, and cannot track changes to any additional providers you may add to your consent form._ - -Google currently is unable to obtain and handle consent for mediation networks, so you'll need to obtain and handle consent for each ad network separately. We are actively working with all of our [open source and versioned][18] mediation networks to provide updated documentation with details on how to forward consent. Documentation is already live for the following mediation networks: - -* [AppLovin](https://developers.google.com/admob/ios/mediation/applovin#eu_consent_and_gdpr) -* [Chartboost](https://developers.google.com/admob/ios/mediation/chartboost#eu_consent_and_gdpr) -* [Facebook](https://developers.google.com/admob/ios/mediation/facebook#eu_consent_and_gdpr) -* [IronSource](https://developers.google.com/admob/ios/mediation/ironsource#eu_consent_and_gdpr) -* [MoPub](https://developers.google.com/admob/ios/mediation/mopub#eu_consent_and_gdpr) -* [myTarget](https://developers.google.com/admob/ios/mediation/mytarget#eu_consent_and_gdpr) -* [Tapjoy](https://developers.google.com/admob/ios/mediation/tapjoy#eu_consent_and_gdpr) -* [Unity Ads](https://developers.google.com/admob/ios/mediation/unity#eu_consent_and_gdpr) -* [Vungle](https://developers.google.com/admob/ios/mediation/vungle#eu_consent_and_gdpr) - -## Update consent status - -When using the Consent SDK, it is recommended that you determine the status of a user's consent at **every app launch**. To do this, call `RequestConsentInfoUpdate` method on an instance of `ConsentInformation`: - -```csharp -using Google.MobileAds.Consent; - -... - -public override void ViewDidLoad () -{ - base.ViewDidLoad (); - - ConsentInformation.SharedInstance.RequestConsentInfoUpdate (new [] { "pub-0123456789012345" }, HandleConsentInformationUpdate;); - - void HandleConsentInformationUpdate (NSError error) - { - if (error != null) { - // Consent info update failed. - return; - } - - // Consent info update succeeded. The shared PACConsentInformation - // instance has been updated. - } -} -``` - -The call to `RequestConsentInfoUpdate` requires two arguments: - -* An array of publisher IDs that your app requests ads from. [Find your publisher ID.][19] -* A block that accepts an `NSError` as an input parameter, which provides information on a failed consent update request. - -An async/await version of this: - -```csharp -try { - await ConsentInformation.SharedInstance.RequestConsentInfoUpdateAsync (new [] { "pub-0123456789012345" }); - - // Consent info update succeeded. The shared PACConsentInformation - // instance has been updated. -} catch (NSErrorException ex) { - // Consent info update failed. -} -``` - -If consent information is successfully updated, `ConsentInformation.SharedInstance.ConsentStatus` provides the updated consent status. It may have the values listed below: - -| Consent State | Definition | -|-------------------------------|---------------------------------------------------------------------------------------------| -| ConsentStatus.Personalized | The user has granted consent for personalized ads. | -| ConsentStatus.NonPersonalized | The user has granted consent for non-personalized ads. | -| ConsentStatus.Unknown | The user has neither granted nor declined consent for personalized or non-personalized ads. | - -Once consent information is successfully updated, you can also check `ConsentInformation.SharedInstance.IsRequestLocationInEeaOrUnknown` to see if the user is located in the European Economic Area or the request location is unknown. - -If the `IsRequestLocationInEeaOrUnknown` property is `false`, the user is not located in the European Economic Area and consent is not required under the [EU User Consent Policy][16]. You can make ad requests to the Google Mobile Ads SDK. - -If the `IsRequestLocationInEeaOrUnknown` property is `true`: - -* If the `ConsentStatus` is `ConsentStatus.Personalized` or `ConsentStatus.NonPersonalized`, the user has already provided consent. You can now [forward consent to the Google Mobile Ads SDK](#forward-consent-to-the-google-mobile-ads-sdk). -* If the user has an `ConsentStatus.Unknown` consent, see the Collect consent section below, which describes the use of utility methods to collect consent. - -## Collect consent - -Google's Consent SDK provides two ways to collect consent from a user: - -* Present a [Google-rendered consent form](#google-rendered-consent-form) to the user. -* Request the list of ad technology providers and collect consent yourself with the [Publisher-managed consent collection](#publisher-managed-consent-collection) option. - -Remember to provide users with the option to [Change or revoke consent](#change-or-revoke-consent). - -### Google-rendered consent form - - - -The Google-rendered consent form is a full-screen configurable form that displays over your app content. You can configure the form to present the user with combinations of the following options: - -* Consent to view personalized ads -* Consent to view non-personalized ads -* Use a paid version of the app instead of viewing ads - -You should review the consent text carefully: what appears by default is a message that **might** be appropriate if you use Google to monetize your app; but we cannot provide legal advice on the consent text that is appropriate for you. To update consent text of the Google-rendered consent form, modify the `consentform.html` file located at Xamarin Bulld Download cache. By default, the file is located at: - -* **Windows:** `$(LocalAppData)\XamarinBuildDownloadCache\GCnsnt-$(Version)\googleads-consent-sdk-ios-$(Version)\PersonalizedAdConsent\PersonalizedAdConsent\PersonalizedAdConsent.bundle` -* **Mac:** `$(HOME)\Library\Caches\XamarinBuildDownload\GCnsnt-$(Version)\googleads-consent-sdk-ios-$(Version)\PersonalizedAdConsent\PersonalizedAdConsent\PersonalizedAdConsent.bundle` - -> ![note_icon] _**Important:**_ _The Google-rendered consent form is not supported if any of your publisher IDs use the commonly used set of ad technology providers. Attempting to load the Google-rendered consent form will always fail in this case._ -> -> _If your publisher IDs use a custom set of providers, and the custom set of ad technology providers exceeds 12, the form removes the personalized ads option. To collect personalized consent for more than 12 ad technology providers, you must use the [Publisher-managed consent collection](#publisher-managed-consent-collection) option._ - -The Google rendered consent form is configured and displayed using the `ConsentForm` class. The following code demonstrates how to build a `ConsentForm` with all three form options: - -```csharp -// TODO: Replace with your app's privacy policy url. -var url = new NSUrl ("https://www.your.com/privacyurl"); -var form = new ConsentForm (url) { - ShouldOfferPersonalizedAds = true, - ShouldOfferNonPersonalizedAds = true, - ShouldOfferAdFree = true -}; -``` - -The properties of `ConsentForm` are described in further detail below: - -* `ShouldOfferPersonalizedAds` - * Indicates whether the consent form should show a personalized ad option. Defaults to YES. - -* `ShouldOfferNonPersonalizedAds` - * Indicates whether the consent form should show a non-personalized ad option. Defaults to YES. - -* `ShouldOfferAdFree` - * Indicates whether the consent form should show an ad-free app option. Defaults to NO. - -### Load consent form - -Once you have created and configured a `ConsentForm` object, load the consent form by invoking the `Load` method of `ConsentForm`, as shown below: - -```csharp -form.Load (HandleLoadCompletionHandler); - -void HandleLoadCompletionHandler (NSError error) -{ - if (error != null) { - // Handle error. - return; - } - - // Load successful. -} - -// async/await version - -try { - await form.LoadAsync (); - // Load successful. -} catch (NSErrorException ex) { - // Handle error. -} -``` - -### Show consent form - -To present the user with the Google-rendered consent form, call `Present` on a loaded ConsentForm, as demonstrated below: - -```csharp -form.Present (this, HandleDismissCompletion); - -void HandleDismissCompletion (NSError error, bool userPrefersAdFree) -{ - if (error == null) { - // Handle error. - return; - } - - if (userPrefersAdFree) { - // User prefers to use a paid version of the app. - } else { - // Check the user's consent choice. - var status = ConsentInformation.SharedInstance.ConsentStatus; - } -} - -// async/await version - -var dismissCompletionResult = await form.PresentAsync (this); - -if (dismissCompletionResult.Error == null) { - // Handle error. - return; -} - -if (dismissCompletionResult.UserPrefersAdFree) { - // User prefers to use a paid version of the app. -} else { - // Check the user's consent choice. - var status = ConsentInformation.SharedInstance.ConsentStatus; -} -``` - -The call to `Present` requires two arguments: - -* A `UIViewController` to present from. -* A block that accepts an `NSError` and a `bool` as input parameters. The `NSError` provides information if there was an error showing the consent form. The `userPrefersAdFree` `bool` has a value of `true` when the user chose to use a paid version of the app in lieu of viewing ads. - -After the user selects an option and closes the form, the Consent SDK saves the user's choice and calls the block. You can read the user's choice and [forward consent to the Google Mobile Ads SDK](#forward-consent-to-the-google-mobile-ads-sdk). - -### Publisher-managed consent collection - -If you choose to get consent yourself, you can use the `AdProviders` property of the `ConsentInformation` class to get the ad technology providers associated with the publisher IDs used in your app. Note that consent is required for the full list of ad technology providers configured for your publisher IDs. - -> ![note_icon] _**Note:**_ _Before you access the `AdProviders` property of `ConsentInformation`, you must wait for the successful update of user's consent status as described in the Update consent status section._ - -```csharp -var adProviders = ConsentInformation.SharedInstance.AdProviders; -``` - -You can then use the list of ad providers to obtain consent yourself. - -### Storing publisher managed consent - -Upon getting consent, record the `ConsentStatus` corresponding to the user's response using the `Status` property of the `ConsentInformation` class. - -```csharp -ConsentInformation.SharedInstance.ConsentStatus = ConsentStatus.Personalized; -``` - -After reporting consent to the Consent SDK, you can [forward consent to the Google Mobile Ads SDK](#forward-consent-to-the-google-mobile-ads-sdk). - -### Change or revoke consent - -> ![note_icon] _**Key Point:**_ _It is important that the user is able to change or revoke the consent they have provided at any time._ - -To allow users to update their consent, simply repeat the steps outlined in the [Collect consent](#collect-consent) section when the user chooses to update their consent status. - -### Users under the age of consent - -If a publisher is aware that the user is under the age of consent, all ad requests must set TFUA (Tag For Users under the Age of Consent in Europe). To include this tag on all ad requests made from your app, set the `TagForUnderAgeOfConsent` property to `true`. This setting takes effect for all future ad requests: - -```csharp -ConsentInformation.SharedInstance.TagForUnderAgeOfConsent = true; -``` - -Once the TFUA setting is enabled, the Google rendered consent form will fail to load. All ad requests that include TFUA will be made ineligible for personalized advertising and remarketing. TFUA disables requests to third-party ad technology providers, such as ad measurement pixels and third-party ad servers. - -To remove TFUA from ad requests, set the `TagForUnderAgeOfConsent` property to `false`. - -## Testing - -The Consent SDK has different behaviors depending on the value of `ConsentInformation.SharedInstance.RequestLocationInEeaOrUnknown`. For example, the consent form fails to load if the user is not located in the EEA. - -To enable easier testing of your app both inside and outside the EEA, the Consent SDK supports debug options that you can set prior to calling any other methods in the Consent SDK. - -1. Grab your device's advertising ID. You can write the following code to log your advertising ID: - ```csharp - using AdSupport; - - Console.WriteLine ($"Advertising ID: {ASIdentifierManager.SharedManager.AdvertisingIdentifier.AsString ()}"); - ``` - - And then check the console to get it: - - ``` - Advertising ID: 41E538F6-9C98-4EF2-B3EE-D7BD8CAF8339 - ``` -2. Whitelist your device to be a debug device using the advertising ID from the console: - ```csharp - ConsentInformation.SharedInstance.DebugIdentifiers = new [] { "41E538F6-9C98-4EF2-B3EE-D7BD8CAF8339" }; - ``` - - > ![warning_icon] _**Warning:**_ _We highly discourage directly setting debugIdentifiers to the current device's advertising ID. You don't want to run the risk of releasing your app with code in place that overwrites every user's geography._ - - > ![note_icon] _**Note:**_ _Simulators are automatically added as debug devices and don't need to be whitelisted._ -3. Finally, set the debugGeography to your preferred geography for testing purposes - ```csharp - // Geography appears as in EEA for debug devices. - ConsentInformation.SharedInstance.DebugGeography = DebugGeography.Eea; - - // Geography appears as not in EEA for debug devices. - ConsentInformation.SharedInstance.DebugGeography = DebugGeography.NotEea; - ``` - -After completing these steps, calls to [update consent status](#update-consent-status) will take into account your debug geography. - -## Forward consent to the Google Mobile Ads SDK - -> ![note_icon] _**Note:**_ _The code in this section can be used with any version of the Google Mobile Ads SDK. It can also be used regardless of whether you used the Consent SDK to gather consent._ - -The default behavior of the Google Mobile Ads SDK is to serve personalized ads. If a user has consented to receive only non-personalized ads, you can configure an GADRequest object with the following code to specify that only non-personalized ads should be requested: - -```csharp -var data = new Dictionary { { "npa", "1" } }; - -var request = Request.GetDefaultRequest (); -var extras = new Extras { - AdditionalParameters = NSDictionary.FromObjectsAndKeys (data.Values.ToArray (), data.Keys.ToArray (), data.Keys.Count) -}; -request.RegisterAdNetworkExtras (extras); -``` - -> ![note_icon] _**Note:**_ _Google's [EU User Consent Policy][16] requires that you collect consent for the full list of ad technology providers configured for your publisher IDs before displaying personalized ads, even if you are using a third-party mediation solution to send ad request to Google._ - -If non-personalized ads are requested, the ad request URL currently includes `&npa=1`. However, note that this is an internal implementation detail of the Google Mobile Ads SDK and is subject to change. - -## FAQ - -**How many ad technology providers does the Consent SDK support?** - -The Consent SDK does not impose a limit on the number of ad technology providers a publisher chooses to enable. However, the Google-rendered consent form supports a maximum of 12 ad technology providers. Publishers with more than 12 ad technology providers can create and manage their own consent form using the ad technology partners fetched from the Consent SDK. - -**Does the list of ad technology providers returned by the SDK automatically update if I change my selection in the AdMob UI?** - -Yes, if you make changes to the list of ad technology providers in the AdMob UI, the changes will propagate to Google’s ad servers in approximately one hour. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/admob/ios/quick-start) to see original Firebase documentation._ - -[1]: https://firebase.google.com/console/ -[2]: http://support.google.com/firebase/answer/7015592 -[3]: https://apps.admob.com/#account/appmgmt: -[4]: https://support.google.com/admob/answer/6240809 -[5]: https://support.google.com/dfp_premium/answer/6075370 -[6]: https://support.google.com/admob/answer/7187428 -[7]: https://support.google.com/dfp_premium/answer/6366881?visit_id=1-636620822163502235-512919786&rd=1 -[8]: https://developers.google.com/mobile-ads-sdk/docs/dfp/ios/targeting -[9]: https://support.google.com/admob/answer/6373176 -[10]: https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html -[11]: https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32016R0679https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html -[12]: https://support.google.com/admob/answer/7666366 -[13]: https://support.google.com/admob/answer/7562142 -[14]: https://developers.google.com/admob/ios/reporting -[15]: https://developer.apple.com/library/archive/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/Introduction/Introduction.html -[16]: https://www.google.com/about/company/user-consent-policy.html -[17]: https://support.google.com/admob/answer/7676680 -[18]: https://developers.google.com/admob/ios/mediation/#choosing_your_mediation_networks -[19]: https://support.google.com/admob/answer/2784578 -[note_icon]: https://cdn3.iconfinder.com/data/icons/UltimateGnome/22x22/apps/gnome-app-install-star.png -[warning_icon]: https://cdn2.iconfinder.com/data/icons/freecns-cumulus/32/519791-101_Warning-20.png -[deprecated_icon]: https://cdn2.iconfinder.com/data/icons/freecns-cumulus/16/519643-144_Forbidden-20.png "Deprecated" diff --git a/docs/Firebase/CrashReporting/Details.md b/docs/Firebase/CrashReporting/Details.md deleted file mode 100755 index f39b39c7a..000000000 --- a/docs/Firebase/CrashReporting/Details.md +++ /dev/null @@ -1,39 +0,0 @@ -## **Important note:** *This component is only compatible with Xamarin Studio and Visual Studio for Mac.* - -Firebase Crash Reporting uses shell scripts to upload symbols to Firebase Console, but scripts use commands that are only available in Mac. Therefore, this component is only compatible with Xamarin Studio and Visual Studio for Mac. - -# Firebase Crash Reporting on iOS - -Comprehensive and actionable information to help diagnose and fix problems in your app. - -Crash Reporting creates detailed reports of the errors in your app. Errors are grouped into clusters of similar stack traces and triaged by the severity of impact on your users. In addition to automatic reports, you can log custom events to help capture the steps leading up to a crash. - -## Key capabilities - -| | | -|-:|--| -| **Monitor fatal errors** | Monitor fatal errors in iOS. Reports are triaged by the severity of impact on users. | -| **Collect the data you need to diagnose problems** | Each report contains a full stack trace as well as device characteristics, performance data, and user circumstances when the error took place. Similar reports are automatically clustered to make it easier to identify related bugs. | -| **Email alerts** | Enable email alerts to receive frequent updates when new crashes are uncovered or regressions are detected. | -| **Integrate with Analytics** | Errors captured are set as **app_exception** events in Firebase Analytics, allowing you to filter audiences based on who sees errors. In addition to stack traces, Crash Reporting also integrates with Analytics to provide you with the list of events that preceded a crash. This information helps to simplify your debugging process. | -| **Free and easy** | Crash Reporting is free to use. Once you've added Firebase to your app, it's just a few lines of code to enable comprehensive error reporting. | - -## User privacy - -Firebase Crash Reporting does not itself collect any personally identifiable information (such as names, email addresses, or phone numbers). Developers can collect additional data using Crash Reporting with log and exception messages. Such data collected through Crash Reporting should not contain information that personally identifies an individual to Google. - -Here is an example of a log message that does not contain personally identifiable information: - -```csharp -Firebase.CrashReporting.CrashReporting.Log ("SQL database failed to initialize"); -``` - -And here is another one that does contain personally identifiable information: - -```csharp -Firebase.CrashReporting.CrashReporting.Log ($"{user.Email} purchased product {product.Id}"); -``` - -If identifying a user is necessary to diagnose an issue, then you must use adequate obfuscation measures to render the data you send to Google anonymous. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/crash/) to see original Firebase documentation._ diff --git a/docs/Firebase/CrashReporting/GettingStarted.md b/docs/Firebase/CrashReporting/GettingStarted.md deleted file mode 100755 index 8731ed724..000000000 --- a/docs/Firebase/CrashReporting/GettingStarted.md +++ /dev/null @@ -1,157 +0,0 @@ -## **Important note:** *This component is only compatible with Xamarin Studio and Visual Studio for Mac.* - -Firebase Crash Reporting uses shell scripts to upload symbols to Firebase Console, but scripts use commands that are only available in Mac. Therefore, this component is only compatible with Xamarin Studio and Visual Studio for Mac. - -# Use Firebase Crash Reporting on iOS - -Firebase Crash Reporting creates detailed reports of the errors in your app. Errors are grouped into clusters of similar stack traces, and triaged by the severity of impact on your users. In addition to automatic reports, you can log custom events to help capture the steps leading up to a crash. - -## Table of Content - -- [User privacy](#user-privacy) -- [Add Firebase to your app](#add-firebase-to-your-app) -- [Configure Crash Reporting in your app](#configure-crash-reporting-in-your-app) -- [Create your first error](#create-your-first-error) -- [Upload symbol files](#upload-symbol-files) - - [Upload symbol files with Visual Studio](#upload-symbol-files-with-visual-studio) - - [Upload symbol files with Terminal](#upload-symbol-files-with-terminal) -- [Upload your first error to Firebase](#upload-your-first-error-to-firebase) -- [Create custom logs](#create-custom-logs) - - [Known issues](#known-issues) - -## User privacy - -Firebase Crash Reporting does not itself collect any personally identifiable information (such as names, email addresses, or phone numbers). Developers can collect additional data using Crash Reporting with log and exception messages. Such data collected through Crash Reporting should not contain information that personally identifies an individual to Google. - -Here is an example of a log message that does not contain personally identifiable information: - -```csharp -Firebase.CrashReporting.CrashReporting.Log ("SQL database failed to initialize"); -``` - -And here is another one that does contain personally identifiable information: - -```csharp -Firebase.CrashReporting.CrashReporting.Log ($"{user.Email} purchased product {product.Id}"); -``` - -If identifying a user is necessary to diagnose an issue, then you must use adequate obfuscation measures to render the data you send to Google anonymous. - -## Add Firebase to your app - -1. Create a Firebase project in the [Firebase console][1], if you don't already have one. If you already have an existing Google project associated with your mobile app, click **Import Google Project**. Otherwise, click **Create New Project**. -2. Click **Add Firebase to your iOS app** and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just [download the config file][2]. -3. When prompted, enter your app's bundle ID. It's important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project. -4. At the end, you'll download a `GoogleService-Info.plist` file. You can [download this file][2] again at any time. - -## Configure Crash Reporting in your app - -Once you have your `GoogleService-Info.plist` file downloaded in your computer, do the following steps in Xamarin Studio: - -1. Add `GoogleService-Info.plist` file to your app project. -2. Set `GoogleService-Info.plist` **build action** behaviour to `Bundle Resource` by Right clicking/Build Action. -3. Add the following line of code somewhere in your app, typically in your AppDelegate's `FinishedLaunching` method (don't forget to import `Firebase.Core` and `Firebase.CrashReporting` namespaces): - -```csharp -CrashReporting.Configure (); -App.Configure (); -``` - -## Create your first error - -Add a crash code right after Firebase initialization call in your AppDelegate's `FinishedLaunching` method to cause a crash when the app launches: - -```csharp -App.Configure (); - -// Cause crash code -var crash = new NSObject (); -crash.PerformSelector (new Selector ("doesNotRecognizeSelector"), crash, 0); -``` - -Don't run the app yet, please read **Upload symbol files** before running. - -## Upload symbol files - -In order to view human-readable crash reports, you will need to upload symbol files to Firebase Console after each build. To achieve this, you will need to upload the executable of your app that is generated after each build (the executable file lives inside of **Your.app** that is generated commonly inside of **bin** folder of your project). But first, you will need to download the **service account key** to authenticate your uploads: - -1. Go to [Firebase Console][1] and select your project. -2. Open **project settings** and go to **Service Accounts** tab. -3. Select **Crash Reporting** and click on **Generate New Private Key** button. -4. Name the file as **service-account.json** and save it in the root of your project folder. - -### Upload symbol files with Visual Studio - -Follow these steps to upload your app symbols with Xamarin Studio: - -* In Visual Studio, open **Project Options** of your app and go to **Build** > **Custom Commands**. -* Double check that **Debug** configuration and **iPhone** platform is selected. -* In Combobox select **After Build** option. -* Paste the following command in **Command** text field: - -``` -sh ${ProjectDir}/scripts/FirebaseCrashReporting/xamarin_upload_symbols.sh -n ${ProjectName} -b ${TargetDir} -i ${ProjectDir}/Info.plist -p ${ProjectDir}/GoogleService-Info.plist -s ${ProjectDir}/service-account.json -``` - -* Save options changed. -* Now, build your app with **Debug** configuration. - -Depending of your internet connection, the build can take some minutes because the script is uploading your symbols to Firebase. - -> ***Note:*** *If you don't want to keep uploading your symbols after each build, just remove the **After Build** command.* - -### Upload symbol files with Terminal - -Follow these steps to upload your app symbols with Terminal: - -* In Xamarin Studio, select **Debug** configuration, **iPhone** Platform and build the app (cmd + k) (don't run it). -* In Terminal, go to your project folder and run the following command: - -``` -# Don't forget to replace [YourAppName] value -sh scripts/FirebaseCrashReporting/xamarin_upload_symbols.sh -n [YourAppName] -b bin/iPhone/Debug -i Info.plist -p GoogleService-Info.plist -s service-account.json -``` - -* Depending of your internet connection, the script can take some minutes because it's uploading your symbols to Firebase. - -## Upload your first error to Firebase - -After you uploaded your symbol files to Firebase, do the following steps to view your crash in Firebase Console: - -1. Launch the app from Xamarin Studio. -2. Wait until your app crashes, then, stop the debugging. -3. Launch the app directly from the home screen on the device. -4. Wait until your app crashes. -5. Remove the crashing line so your app can start successfully. -6. Run your app again. -7. Within 20 minutes your crash should show up in **Crash Reporting** section of Firebase Console. - -## Create custom logs - -You can use `Log` method to create custom log messages that are included in your crash reports. The following example demonstrates creating a log message: - -```csharp -using Firebase.CrashReporting; - -// ... - -CrashReporting.Log ("Cause Crash button clicked"); - -// Cause crash code -var crash = new NSObject (); -crash.PerformSelector (new Selector ("doesNotRecognizeSelector"), crash, 0); -``` - -> _**Note:**_ _The string given to this method must be an escaped string due it will be passed to a C function and it expects an escaped string. For example, if you want to print a %, you must type %%. Passing an unescaped string may cause the termination of your app._ - -### Known issues - -* App doesn't compile when `Incremental builds` is enabled. (Bug [#43689][3]) -* The Firebase SDK does not currently support using the `NSException` class in the Xcode simulator. If you use this class, it will result in malformed stack traces in the Firebase console. As a workaround, either use a physical device or test with a different type of exception. -* Crash Reporting uses a unique ID to identify each user. Due to a known bug in Xcode 8.1, creating this ID fails on iOS 10 simulators, preventing the upload of error reports. To work around this in Xcode 8.1, you can run tests on a device, or turn on **Keychain Sharing** in your **Entitlements.plist** file. This bug has been addressed in the beta release of Xcode 8.2. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/crash/ios) to see original Firebase documentation._ - -[1]: https://firebase.google.com/console/ -[2]: http://support.google.com/firebase/answer/7015592 -[3]: https://bugzilla.xamarin.com/show_bug.cgi?id=43689 diff --git a/docs/Firebase/DynamicLinks/Details.md b/docs/Firebase/DynamicLinks/Details.md deleted file mode 100755 index b2a04c0bb..000000000 --- a/docs/Firebase/DynamicLinks/Details.md +++ /dev/null @@ -1,20 +0,0 @@ -Firebase Dynamic Links are links that work the way you want, on multiple platforms, and whether or not your app is already installed. - -With Dynamic Links, your users get the best available experience for the platform they open your link on. If a user opens a Dynamic Link on iOS or Android, they can be taken directly to the linked content in your native app. If a user opens the same Dynamic Link in a desktop browser, they can be taken to the equivalent content on your website. - -In addition, Dynamic Links work across app installs: if a user opens a Dynamic Link on iOS or Android and doesn't have your app installed, the user can be prompted to install it; then, after installation, your app starts and can access the link. - -## How does it work? - -You create a Dynamic Link either by using the Firebase console, using a REST API, iOS or Android Builder API, or by forming a URL by adding Dynamic Link parameters to a domain specific to your app. These parameters specify the links you want to open, depending on the user's platform and whether your app is installed. - -When a user opens one of your Dynamic Links, if your app isn't yet installed, the user is sent to the Play Store or App Store to install your app (unless you specify otherwise), and your app opens. You can then retrieve the link that was passed to your app and handle the link as appropriate for your app. - -| | | -|--|--| -| Set up Firebase and the Dynamic Links SDK | Enable Firebase Dynamic Links for your Firebase project in the Firebase console. Then, include the Dynamic Links SDK in your app. | -| Create Dynamic Links | You can create Dynamic Links programmatically or by using the Firebase console. | -| Handle Dynamic Links in your app | When your app opens, use the Dynamic Links SDK to check if a Dynamic Link was passed to it. If so, get the deep link from the Dynamic Link data and handle the deep link as necessary. | -| View analytics data | Track the performance of your Dynamic Links in the Firebase console. | - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/dynamic-links/) to see original Firebase documentation._ \ No newline at end of file diff --git a/docs/Firebase/DynamicLinks/GettingStarted.md b/docs/Firebase/DynamicLinks/GettingStarted.md deleted file mode 100755 index 1318e4a84..000000000 --- a/docs/Firebase/DynamicLinks/GettingStarted.md +++ /dev/null @@ -1,281 +0,0 @@ -# Firebase Dynamic Links on iOS - -With Firebase Dynamic Links, you can give new users of your app a personalized onboarding experience, and thus increase user sign-ups, user retention, and long-term user engagement. - -Dynamic Links are links into an app that work whether or not users have installed the app yet. When users open a Dynamic Link into an app that is not installed, the app's App Store page opens, where users can install the app. After users install and open the app, the app handles the link. - -An app might handle the link by opening the app's content using custom URL schemes on iOS 8, or handling Universal Links on iOS 9 and newer. Or, an app could handle the link by initiating some app-specific logic such as crediting the user with a coupon, or displaying a specific welcome screen. - -## Table of content - -- [Prerequisites](#prerequisites) -- [Add Firebase to your app](#add-firebase-to-your-app) -- [Configure Dynamic Links in your app](#configure-dynamic-links-in-your-app) -- [Use the iOS Builder API](#use-the-ios-builder-api) - - [Create a long link from parameters](#create-a-long-link-from-parameters) - - [Set the length of a short Dynamic Link](#set-the-length-of-a-short-dynamic-link) - - [Create a short link from a long link](#create-a-short-link-from-a-long-link) -- [Manually constructing a Dynamic Link URL](#manually-constructing-a-dynamic-link-url) -- [Open Dynamic Links in your app](#open-dynamic-links-in-your-app) -- [Known issues](#known-issues) - -## Prerequisites - -Firebase Dynamic Links requires iOS 8 or newer. You can target iOS 7 in your app, but Firebase Dynamic Links SDK calls only function on apps running iOS 8 or newer. - -## Add Firebase to your app - -1. Create a Firebase project in the [Firebase console][1], if you don't already have one. If you already have an existing Google project associated with your mobile app, click **Import Google Project**. Otherwise, click **Create New Project**. -2. Click **Add Firebase to your iOS app** and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just [download the config file][2]. -3. When prompted, enter your app's bundle ID. It's important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project. -4. At the end, you'll download a `GoogleService-Info.plist` file. You can [download this file][2] again at any time. -5. Go to **Project settings**, in **General** tab select your recently created iOS bundle ID. -6. Set your App Store ID, you can find your App Store ID in your app’s URL. (e.g. https://itunes.apple.com/us/app/yourapp/id123456789, **123456789** is your App Store ID). -7. Set your Team ID, you can find your Team ID in the Apple Member Center under the [membership tab][3]. -8. In [Firebase console][1], in your project menu go to Dynamic Links tab, accept the terms of service if you are prompted to do so, copy Url link, paste it into your Navigation bar and add **/apple-app-site-association** (e.g https://app_code.app.goo.gl//apple-app-site-association) -9. Your app is connected if the apple-app-site-association file contains a reference to your app's App Store ID and bundle ID, for example: - -``` -{"applinks":{"apps":[],"details":[{"appID":"1234567890.com.example.ios","paths":["/*"]}]}} -``` - -If the details field is empty, double-check that you specified your Team ID. - -## Configure Dynamic Links in your app - -Once you have your `GoogleService-Info.plist` file downloaded in your computer, do the following steps in Xamarin Studio: - -1. Add `GoogleService-Info.plist` file to your app project. -2. Set `GoogleService-Info.plist` **build action** behaviour to `Bundle Resource` by Right clicking/Build Action. -3. In your `Entitlements.plist` file, enable **Associated Domains**. -4. Add `applinks:app_code.app.goo.gl` to **Domains** where **app_code** is your Dynamic Links identifier. -5. In your `Info.plist` file, go to **Advance** and add an Url Type. -6. Set the **Identifier** field to a unique value and the **URL scheme** field to either your Bundle ID or a unique value. If you set the **URL scheme** to a value other than your Bundle ID, you must specify the Bundle ID when you create your Dynamic Links. -7. Add the following lines of code somewhere in your app, typically in your AppDelegate's `FinishedLaunching` method (don't forget to import `Firebase.Core` namespace): - -```csharp -App.Configure (); -``` - -## Create Dynamic Links - -There are four ways you can create a Dynamic Link: - -* Using the [Firebase console][4]. This is useful if you're creating one-off links to share on social media. -* Using the [Dynamic Link Builder API](#use-the-ios-builder-api). This is the preferred way to dynamically create links in your app for user-to-user sharing or in any situation that requires many links. You can track the performance of Dynamic Links created with the Builder API using the Dynamic Links [Analytics API][5]. -* Using the [REST API][6]. This is the preferred way to dynamically create links on platforms that don't have a Builder API. You can track the performance of Dynamic Links created with the REST API using the Dynamic Links [Analytics API][5]. -* [Manually](#manually-constructing-a-dynamic-link-url). If you don't need to track click data and you don't care if the links are long, you can manually construct Dynamic Links using URL parameters, and by doing so, avoid an extra network round trip. - -## Use the iOS Builder API - -You can create short or long Dynamic Links with the Firebase Dynamic Links iOS Builder API. This API accepts either a long Dynamic Link or an object containing Dynamic Link parameters, and returns a URL like the following example: - -``` -https://abc123.app.goo.gl/WXYZ -``` - -### Create a long link from parameters - -You can create a Dynamic Link programmatically by setting the following parameters and getting the `DynamicLinkComponents.Url` parameter: - -```csharp -var link = NSUrl.FromString (dictionary ["Link"].ToString ()); -var components = DynamicLinkComponents.FromLink (link, Dynamic_Link_Domain); - -var source = dictionary ["Source"].ToString (); -var medium = dictionary ["Medium"].ToString (); -var campaign = dictionary ["Campaign"].ToString (); - -var analyticsParams = DynamicLinkGoogleAnalyticsParameters.FromSource (source, medium, campaign); -analyticsParams.Term = dictionary ["Term"].ToString (); -analyticsParams.Content = dictionary ["Content"].ToString (); -components.AnalyticsParameters = analyticsParams; - -var bundleId = dictionary ["BundleID"].ToString (); - -if (!string.IsNullOrWhiteSpace (bundleId)) { - var iOSParams = DynamicLinkiOSParameters.FromBundleId (bundleId); - iOSParams.FallbackUrl = NSUrl.FromString (dictionary ["FallbackURL"].ToString ()); - iOSParams.MinimumAppVersion = dictionary ["MinimumAppVersion"].ToString (); - iOSParams.CustomScheme = dictionary ["CustomScheme"].ToString (); - iOSParams.IPadBundleId = dictionary ["IPadBundleId"].ToString (); - iOSParams.IPadFallbackUrl = NSUrl.FromString (dictionary ["IPadFallbackUrl"].ToString ()); - iOSParams.AppStoreId = dictionary ["AppStoreId"].ToString (); - components.IOSParameters = iOSParams; - - var appStoreParams = DynamicLinkiTunesConnectAnalyticsParameters.Create (); - appStoreParams.AffiliateToken = dictionary ["AffiliateToken"].ToString (); - appStoreParams.CampaignToken = dictionary ["CampaignToken"].ToString (); - appStoreParams.ProviderToken = dictionary ["ProviderToken"].ToString (); - components.ITunesConnectParameters = appStoreParams; -} - -var packageName = dictionary ["PackageName"].ToString (); - -if (!string.IsNullOrWhiteSpace (packageName)) { - var androidParams = DynamicLinkAndroidParameters.FromPackageName (packageName); - androidParams.FallbackUrl = NSUrl.FromString (dictionary ["FallbackURL"].ToString ()); - androidParams.MinimumVersion = nint.Parse (dictionary ["MinimumAppVersion"].ToString ()); - components.AndroidParameters = androidParams; -} - -var socialParams = DynamicLinkSocialMetaTagParameters.Create (); -socialParams.Title = dictionary ["Title"].ToString (); -socialParams.DescriptionText = dictionary ["DescriptionText"].ToString (); -socialParams.ImageUrl = NSUrl.FromString (dictionary ["ImageUrl"].ToString ()); -components.SocialMetaTagParameters = socialParams; - -var longLink = components.Url; -Console.WriteLine (longLink.AbsoluteString); -``` - -### Set the length of a short Dynamic Link - -You can also set the `PathLength` parameter to specify how the path component of the short Dynamic Link is generated: - -```csharp -var options = DynamicLinkComponentsOptions.Create (); -options.PathLength = ShortDynamicLinkPathLength.Unguessable; -components.Options = options; -``` - -By default, or if you set the parameter to `Unguessable`, the path component will be a 17-character string, like in the following example: - -``` -https://abc123.app.goo.gl/UVWXYZuvwxyz12345 -``` - -Such strings are created by base62-encoding randomly generated 96-bit numbers. Use this setting to prevent your Dynamic Links URLs from being guessed and crawled, which can potentially expose sensitive information to unintended recipients. - -If you set the parameter to `Short`, the path component will be a string that is only as long as needed to be unique, with a minimum length of 4 characters: - -``` -https://abc123.app.goo.gl/WXYZ -``` - -Use this method if sensitive information would not be exposed if a short Dynamic Link URL were guessed. - -### Create a short link from a long link - -You can use the Firebase Dynamic Links API to shorten a long Dynamic Link. To do so, call: - -```csharp -components.GetShortenUrl ((shortUrl, warnings, error) => { - // Handle shortURL or error. - if (error != null) { - Console.WriteLine ($"Error generating short link: {error.LocalizedDescription}"); - return; - } - - Console.WriteLine (shortUrl.AbsoluteString); -}); - -// async/await way: - -try { - var result = await components.GetShortenUrlAsync (); - Console.WriteLine (result.ShortUrl.AbsoluteString); -} catch (NSErrorException ex) { - Console.WriteLine ($"Error generating short link: {ex.Error.LocalizedDescription}"); -} -``` - -### Specifying a custom URL scheme for Dynamic Links - -By default, Dynamic Links uses your app's bundle identifier as the URL scheme needed to open up your application. We recommend staying with this default value to keep your implementation simple. - -However, developers who are already using a custom URL scheme for other purposes may wish to use this same custom URL scheme for their Dynamic Links as well. If you are in this situation, you can specify a different URL scheme for your Firebase Dynamic Links by following these steps: - -1. When setting up your app, make sure you specify the default URL scheme to be used by your application before configuring your FirebaseApp shared instance: - - ```csharp - public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) - { - // Set DeepLinkUrlScheme to the custom URL scheme you defined in your - // Info.plist. - Options.DefaultInstance.DeepLinkUrlScheme = "com.xamarin.firebase.ios.dynamiclinkssample"; - App.Configure (); - - return true; - } - ``` - -2. Whenever you create any Dynamic Link, you will need to specify the custom URL scheme that your app uses. You can do this through the Firebase console, setting the `customScheme` in the Builder API, specifying the `ius` parameter in your URL, or sending the `iosCustomScheme` parameter to the REST API - -## Manually constructing a Dynamic Link URL - -Please, read this [Firebase documentation][7] to learn how to construct a Dynamic Link URL manually. - -## Open Dynamic Links in your app - -You will need to override `OpenUrl (UIApplication, NSUrl, string, NSObject)` method to support iOS 8 or older and `OpenUrl (UIApplication, NSUrl, NSDictionary)` method to support iOS 9 or newer. These methods handle links received through your app's custom URL scheme. These methods are called when your app receives a link on iOS 8 and older, and when your app is opened for the first time after installation on any version of iOS: - -```csharp -// Handle Custom Url Schemes for iOS 9 or newer -public override bool OpenUrl (UIApplication app, NSUrl url, NSDictionary options) -{ - return OpenUrl (app, url, null, null); -} - -// Handle Custom Url Schemes for iOS 8 or older -public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation) -{ - Console.WriteLine ("I'm handling a link through the OpenUrl method."); - - var dynamicLink = DynamicLinks.SharedInstance?.FromCustomSchemeUrl (url); - - if (dynamicLink == null) - return false; - - // Handle the deep link. For example, show the deep-linked content or - // apply a promotional offer to the user's account. - return true; -} -``` - -Override `ContinueUserActivity (UIApplication, NSUserActivity, UIApplicationRestorationHandler)` method to handle links received as [Universal Links][8] on iOS 9 and newer: - -```csharp -// Handle links received as Universal Links on iOS 9 or later -public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler) -{ - return DynamicLinks.SharedInstance.HandleUniversalLink (userActivity.WebPageUrl, (dynamicLink, error) => { - if (error != null) { - System.Console.WriteLine (error.LocalizedDescription); - return; - } - - // Handle Universal Link - }); -} -``` - -## View Dynamic Links Analytics Data - -To help you gauge the effectiveness of your promotions and campaigns, Firebase Dynamic Links provides several ways to view analytics data and integrate with analytics tools. - -To learn more about this, please, read the following [documentation][10]. - -## Debugging Dynamic Links - -To help you debug your Dynamic Links, you can preview your Dynamic Links' behavior on different platforms and configurations with an automatically-generated flowchart. Generate the flowchart by adding the d=1 parameter to any short or long Dynamic Link. For example, app_code.app.goo.gl/path?d=1 for a short Dynamic Link. - -To learn more about this, please, read the following [documentation][11]. - -## Generate link previews with social metadata - -To learn about this, please, read the following [documentation][12]. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/dynamic-links/ios) to see original Firebase documentation._ - -[1]: https://firebase.google.com/console/ -[2]: http://support.google.com/firebase/answer/7015592 -[3]: https://developer.apple.com/account/#/membership -[4]: https://console.firebase.google.com/project/_/durablelinks/links/ -[5]: https://firebase.google.com/docs/reference/dynamic-links/analytics -[6]: https://firebase.google.com/docs/dynamic-links/rest -[7]: https://firebase.google.com/docs/dynamic-links/create-manually -[8]: https://developer.apple.com/library/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html -[10]: https://firebase.google.com/docs/dynamic-links/analytics -[11]: https://firebase.google.com/docs/dynamic-links/debug -[12]: https://firebase.google.com/docs/dynamic-links/link-previews diff --git a/docs/Firebase/Invites/Details.md b/docs/Firebase/Invites/Details.md deleted file mode 100755 index 7c1d509b3..000000000 --- a/docs/Firebase/Invites/Details.md +++ /dev/null @@ -1,39 +0,0 @@ -Firebase Invites are an out-of-the-box solution for app referrals and sharing via email or SMS. - -Word of mouth is one of the most effective ways of getting users to install your app. In a [recent study](https://think.storage.googleapis.com/docs/mobile-app-marketing-insights.pdf) of thousands of smartphone users, researchers found that the #1 reason people discovered an app is because they heard about it from a friend or colleague. Firebase Invites makes it easy to turn your app's users into your app's strongest advocates. - -Firebase Invites builds on Firebase Dynamic Links. which ensures that recipients of links have the best possible experience for their platform and the apps they have installed. - -## Key capabilities - -| | | -|-:|--| -| **Rich sharing that's easy for users** | Firebase Invites makes it simple for users to send content to their friends, over both SMS and email, by ensuring that referral codes, recipe entries, or other shared content gets passed along with the invitation—no cutting-and-pasting required. | -| **Rich sharing that's easy to implement** | Firebase Invites handles the invitation flow for you, allowing you to deliver a straightforward user experience without taking engineering time away from the rest of your app. | -| **Invitations that survive the installation process** | Because Firebase Invites is built on Dynamic Links, invitations work across the App Store and Play Store installation processes and ensure that recipients get the referral code or shared content, whether or not they have your app installed. | - -### Complete list of features - -| Sending invitations | | -|--------------------:|--| -| **Combines the most common sharing channels** | Firebase Invites can be sent over SMS or email. | -| **Merged contacts selector** | The share screen's contact list is populated from the user's Google Contacts and the contacts stored locally on the device. | -| **Recipient recommendations** | The share screen recommends recipients based on the contacts the user communicates with frequently. | -| **Customizable invitation message** | You can set the default message to be sent with invitations. This message can be edited by the user when sending invitations. | -| **Customizable rich-text email invitations** | You can customize email invitations in either of two ways:
  • Provide custom images that will be used along with additional text and graphics from the app's entry in the App Store or Play Store.

  • Provide HTML for a fully customized email invitation.
| - -| Receiving invitations | | -|----------------------:|--| -| **Installation flow initiation** | Firebase Invites smartly directs the recipient to the appropriate store when they open the link and need to install the app. iOS users are sent to the App Store, Android users are sent to the Play Store, and web users are sent to the store for the sender's platform. | -| **Installation flow survival** | Invitations use Dynamic Links, which ensure that the link information contained in the invitation doesn't get lost, even if the user has to install the app first. | -| **Low friction for users** | iOS and Android users can receive invitations without signing in to their Google Accounts. | - -## How does it work? - -![FirebaseInvites_HowItWorks](https://firebase.google.com/docs/invites/images/send-invitations.png) - -When a user taps one of your app's Share buttons and chooses the Firebase Invites channel—usually named "Email and SMS"—the Firebase Invites sharing screen opens. From the sharing screen, the user selects recipients from their Google contacts and contacts stored locally on the device, optionally customizes the invitation message and sends the invitations. Invitations are sent by email or SMS, depending on the available contact information, and contain a Dynamic Link to your app. - -When the invitation's recipients open the Dynamic Link in the invitation, they are sent to the Play Store or App Store if they need to install your app; then, your app opens and can retrieve and handle the link. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/invites/) to see original Firebase documentation._ \ No newline at end of file diff --git a/docs/Firebase/Invites/GettingStarted.md b/docs/Firebase/Invites/GettingStarted.md deleted file mode 100755 index 2ec8d7a03..000000000 --- a/docs/Firebase/Invites/GettingStarted.md +++ /dev/null @@ -1,167 +0,0 @@ -# Send and Receive Firebase Invites from Your iOS App - -## Table of content - -- [Send and Receive Firebase Invites from Your iOS App](#send-and-receive-firebase-invites-from-your-ios-app) - - [Table of content](#table-of-content) - - [Prerequisites](#prerequisites) - - [Add Firebase to your app](#add-firebase-to-your-app) - - [Configure Invites in your app](#configure-invites-in-your-app) - - [Give your app access to your Contacts](#give-your-app-access-to-your-contacts) - - [Handle incoming app invites](#handle-incoming-app-invites) - - [Enable your users to send app invites](#enable-your-users-to-send-app-invites) - -## Prerequisites - -Firebase Invites requires iOS 8 or newer. You can target iOS 7 in your app, but all Firebase Invites SDK calls will be no-ops if the app isn't running on iOS 8 or newer. - -## Add Firebase to your app - -1. Create a Firebase project in the [Firebase console][1], if you don't already have one. If you already have an existing Google project associated with your mobile app, click **Import Google Project**. Otherwise, click **Create New Project**. -2. Click **Add Firebase to your iOS app** and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just [download the config file][2]. -3. When prompted, enter your app's bundle ID. It's important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project. -4. At the end, you'll download a `GoogleService-Info.plist` file. You can [download this file][2] again at any time. -5. Go to **Project settings**, in **General** tab select your recently created iOS bundle ID. -6. Set your App Store ID, you can find your App Store ID in your app’s URL. (e.g. https://itunes.apple.com/us/app/yourapp/id123456789, **123456789** is your App Store ID). -7. Set your Team ID, you can find your Team ID in the Apple Member Center under the [membership tab][3]. -8. You must enable Firebase Dynamic Links to use Firebase Invites. In [Firebase console][1], in your project menu go to Dynamic Links tab, accept the terms of service if you are prompted to do so, copy Url link, paste it into your Navigation bar and add **/apple-app-site-association** (e.g https://app_code.app.goo.gl//apple-app-site-association) -9. Your app is connected if the apple-app-site-association file contains a reference to your app's App Store ID and bundle ID, for example: - -``` -{"applinks":{"apps":[],"details":[{"appID":"1234567890.com.example.ios","paths":["/*"]}]}} -``` - -If the details field is empty, double-check that you specified your Team ID. - -If you haven't created a Dynamic Link follow this [documentation][3]. - -## Configure Invites in your app - -Once you have your `GoogleService-Info.plist` file downloaded in your computer, do the following steps in Xamarin Studio: - -1. Add `GoogleService-Info.plist` file to your app project. -2. Set `GoogleService-Info.plist` **build action** behaviour to `Bundle Resource` by Right clicking/Build Action. -3. Open `GoogleService-Info.plist` file and change `IS_SIGNIN_ENABLED` and `IS_APPINVITE_ENABLED` values to `Yes`. -4. Add the following line of code somewhere in your app, typically in your AppDelegate's `FinishedLaunching` method (don't forget to import `Firebase.Core` namespace): - -```csharp -App.Configure (); -``` - -## Give your app access to your Contacts - -Invites, before sending your invitation, access to your Contacts to show you a list with them so you can invite everyone to try your awesome app! To allow Invites to achieve this, you need to do the following steps in Visual Studio: - -1. Open your `Info.plist` and go to **Source** tab. -2. Add a new entry and search for **Privacy - Contacts Usage Description**. -3. Add your message that will be displayed when Invites tries to access to your contacts as value. For example: "MyRecipeApp uses your contacts to make it easy to share recipes with your friends." - -## Handle incoming app invites - -After you have configured your app, you must next enable your app to handle incoming app invites. - -When a user selects an incoming app invite on their iOS device, if the user has not yet installed your app, they can choose to install your app from its iTunes App Store page. When the user opens your app for the first time, it's important for your app to provide a personalized onboarding experience to increase the likelihood they will become an engaged, long-term user of your app. To help you do this, the Invites SDK provides the deeplink and invitation ID associated with the app invite received by the user. - -> ![note_icon] **_Note:_** _If the Invites SDK indicates a weak match for a deeplink, it means that the match between the deeplink and the receiving device may not be perfect. In this case your app should reveal no personal information from the deeplink._ - -```csharp -// Support for iOS 9 or later -public override bool OpenUrl (UIApplication app, NSUrl url, NSDictionary options) -{ - var openUrlOptions = new UIApplicationOpenUrlOptions (options); - return OpenUrl (app, url, openUrlOptions.SourceApplication, openUrlOptions.Annotation); -} - -// Support for iOS 8 or before -public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation) -{ - // Handle Sign In - if (SignIn.SharedInstance.HandleUrl (url, sourceApplication ?? "", annotation)) - return true; - - // Handle App Invite requests - return Invites.HandleUniversalLink (url, HandleInvitesUniversalLink); - - void HandleInvitesUniversalLink (ReceivedInvite receivedInvite, NSError error) - { - // ... - } -} -``` - -## Enable your users to send app invites - -Now that your app is ready to handle incoming invites correctly, it is time to enable your app to send invitations to the user's contacts. - -Before a user can send Invites, the user must be signed in with their Google Account. Follow [Google Sign-In getting started][4] to integrate Sign-In into your -app. - -To send invitations, first declare a class that implements the `IInviteDelegate` interface: - -```csharp -public class ViewController : UIViewController, IInviteDelegate -``` - -Then, add a **Send Invitation** button to your app. You can add this button as an option in your main menu, or add this button alongside your deep-linkable content, so that users can send specific content along with the invitation. See the [Firebase Invites best practices][5]. - -When users tap your **Send Invitation** button, open the invitation dialog: - -```csharp -// NOTE: You must have the App Store ID set in your developer console project -// in order for invitations to successfully be sent. -public void SendInvite () -{ - // When you create the invitation dialog, you must specify the title - // of the invitation dialog and the invitation message to send. - // You can also customize the image and deep link URL that - // get sent in the invitation - var inviteDialog = Invites.GetInviteDialog (); - inviteDialog.SetInviteDelegate (this); - inviteDialog.SetTitle ("Invites Sample"); - - // A message hint for the dialog. Note this manifests differently depending on the - // received invitation type. For example, in an email invite this appears as the subject. - inviteDialog.SetMessage ($"Try this out! {anUrl}"); - - // These following values are optionals and are only sent via email - inviteDialog.SetDeepLink ("app_url"); - inviteDialog.SetDescription ("A description of the app"); - inviteDialog.SetCustomImage ("The url of the image"); - inviteDialog.SetCallToActionText ("Button title of the invitations"); - - // If you have an Android version of your app and you want to send - // an invitation that can be opened on Android in addition to iOS - var targetApp = new InvitesTargetApplication { AndroidClientId = "Android ID" }; - inviteDialog.SetOtherPlatformsTargetApplication (targetApp); - - inviteDialog.Open (); -} -``` - -If you want to learn more about Invitation parts, see the following [documentation][6]. - -The `SendInvite` method above then opens the contact chooser dialog where the user selects the contacts to invite. Invitations are sent by email or SMS. After the user sends the invitation, your app receives a callback to the `InviteFinished` method of `IInviteDelegate` interface: - -```csharp -[Export ("inviteFinishedWithInvitations:error:")] -public void InviteFinished (string [] invitationIds, NSError error) -{ - if (error == null) { - foreach (var id in invitationIds) - System.Console.WriteLine (id); - } else { - System.Console.WriteLine (error.LocalizedDescription); - } -} -``` - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/invites/ios) to see original Firebase documentation._ - -[1]: https://firebase.google.com/console/ -[2]: http://support.google.com/firebase/answer/7015592 -[3]: https://firebase.google.com/docs/dynamic-links/ios#create-a-dynamic-link -[4]: https://components.xamarin.com/gettingstarted/googleiossignin -[5]: https://firebase.google.com/docs/invites/best-practices -[6]: https://firebase.google.com/docs/invites/ios#customize-the-invitation -[note_icon]: https://cdn3.iconfinder.com/data/icons/UltimateGnome/22x22/apps/gnome-app-install-star.png -[warning_icon]: https://cdn2.iconfinder.com/data/icons/freecns-cumulus/32/519791-101_Warning-20.png \ No newline at end of file diff --git a/docs/Firebase/MLKit.ModelInterpreter/Details.md b/docs/Firebase/MLKit.ModelInterpreter/Details.md deleted file mode 100755 index e9cc7b712..000000000 --- a/docs/Firebase/MLKit.ModelInterpreter/Details.md +++ /dev/null @@ -1,19 +0,0 @@ -# Custom Models - -If you're an experienced ML developer and ML Kit's pre-built models don't meet your needs, you can use a custom [TensorFlow Lite][1] model with ML Kit. - -Host your TensorFlow Lite models using Firebase or package them with your app. Then, use the ML Kit SDK to perform inference using the best-available version of your custom model. If you host your model with Firebase, ML Kit automatically updates your users with the latest version. - -## Key capabilities - -| | | -|--|--| -| **TensorFlow Lite model hosting** | Host your models using Firebase to reduce your app's binary size and to make sure your app is always using the most recent version available of your model. | -| **On-device ML inference** | Perform inference in an iOS or Android app by using the ML Kit SDK to run your custom TensorFlow Lite model. The model can be bundled with the app, hosted in the Cloud, or both. | -| **Automatic model fallback** | Specify multiple model sources; use a locally-stored model when the Cloud-hosted model is unavailable. | -| **Automatic model updates** | Configure the conditions under which your app automatically downloads new versions of your model: when the user's device is idle, is charging, or has a Wi-Fi connection. | - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/ml-kit/use-custom-models) to see original Firebase documentation._ - -[1]: https://www.tensorflow.org/mobile/tflite/ - diff --git a/docs/Firebase/MLKit.ModelInterpreter/GettingStarted.md b/docs/Firebase/MLKit.ModelInterpreter/GettingStarted.md deleted file mode 100755 index 68666eff2..000000000 --- a/docs/Firebase/MLKit.ModelInterpreter/GettingStarted.md +++ /dev/null @@ -1,268 +0,0 @@ -# Use a TensorFlow Lite model for inference with ML Kit on iOS - -You can use ML Kit to perform on-device inference with a TensorFlow Lite model. - -ML Kit can use TensorFlow Lite models only on devices running iOS 9 and newer. - -## Table of Content - -- [Use a TensorFlow Lite model for inference with ML Kit on iOS](#use-a-tensorflow-lite-model-for-inference-with-ml-kit-on-ios) - - [Table of Content](#table-of-content) - - [Add Firebase to your app](#add-firebase-to-your-app) - - [Configure MLKit in your app](#configure-mlkit-in-your-app) - - [Host or bundle your model](#host-or-bundle-your-model) - - [Host models on Firebase](#host-models-on-firebase) - - [Bundle models with an app](#bundle-models-with-an-app) - - [Load the model](#load-the-model) - - [Configure a Firebase-hosted model source](#configure-a-firebase-hosted-model-source) - - [Configure a local model source](#configure-a-local-model-source) - - [Create an interpreter from your model sources](#create-an-interpreter-from-your-model-sources) - - [Specify the model's input and output](#specify-the-models-input-and-output) - - [Perform inference on input data](#perform-inference-on-input-data) - - [Appendix: Model security](#appendix-model-security) -- [Use a custom TensorFlow Lite build](#use-a-custom-tensorflow-lite-build) - - [Prerequisites](#prerequisites) - - [Building the Tensorflow Lite library](#building-the-tensorflow-lite-library) - - [Add your custom TensorFlow Lite framework](#add-your-custom-tensorflow-lite-framework) - -## Add Firebase to your app - -1. Create a Firebase project in the [Firebase console][1], if you don't already have one. If you already have an existing Google project associated with your mobile app, click **Import Google Project**. Otherwise, click **Create New Project**. -2. Click **Add Firebase to your iOS app** and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just [download the config file][2]. -3. When prompted, enter your app's bundle ID. It's important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project. -4. At the end, you'll download a `GoogleService-Info.plist` file. You can [download this file][2] again at any time. - -## Configure MLKit in your app - -Once you have your `GoogleService-Info.plist` file downloaded in your computer, do the following steps in Visual Studio: - -1. Add `GoogleService-Info.plist` file to your app project. -2. Set `GoogleService-Info.plist` **build action** behaviour to `Bundle Resource` by Right clicking/Build Action. -3. Add the following line of code somewhere in your app, typically in your AppDelegate's `FinishedLaunching` method (don't forget to import `Firebase.Core` namespace): - -```csharp -App.Configure (); -``` - -Convert the TensorFlow model you want to use to TensorFlow Lite format. See [TOCO: TensorFlow Lite Optimizing Converter][3]. - -## Host or bundle your model - -Before you can use a TensorFlow Lite model for inference in your app, you must make the model available to ML Kit. ML Kit can use TensorFlow Lite models hosted remotely using Firebase, bundled with the app binary, or both. - -By hosting a model on Firebase, you can update the model without releasing a new app version, and you can use Remote Config and A/B Testing to dynamically serve different models to different sets of users. - -If you choose to only provide the model by hosting it with Firebase, and not bundle it with your app, you can reduce the initial download size of your app. Keep in mind, though, that if the model is not bundled with your app, any model-related functionality will not be available until your app downloads the model for the first time. - -By bundling your model with your app, you can ensure your app's ML features still work when the Firebase-hosted model isn't available. - -> ![note_icon] _Before you use a custom model in a publicly-available app, be aware of the [security implications][4]._ - -### Host models on Firebase - -To host your TensorFlow Lite model on Firebase: - -1. In the **ML Kit** section of the [Firebase console][1], click the **Custom** tab. -2. Click **Add custom model** (or **Add another model**). -3. Specify a name that will be used to identify your model in your Firebase project, then upload the TensorFlow Lite model file (usually ending in `.tflite` or `.lite`). - -After you add a custom model to your Firebase project, you can reference the model in your apps using the name you specified. At any time, you can upload a new TensorFlow Lite model, and your app will download the new model and start using it when the app next restarts. You can define the device conditions required for your app to attempt to update the model (see below). - -### Bundle models with an app - -To bundle your TensorFlow Lite model with your app, add the model file (usually ending in `.tflite` or `.lite`) into the **Resources** folder in your Visual Studio project, or, add it anywhere on your project tree and change **build action** behaviour to `Bundle Resource` by Right clicking/Build Action. The model file will be included in the app bundle and available to ML Kit. - -## Load the model - -To use your TensorFlow Lite model in your app, first configure ML Kit with the locations where your model is available: on the cloud using Firebase, in local storage, or both. If you specify both a local and cloud model source, ML Kit will use the cloud source if it is available, and fall back to the locally-stored model if the cloud source isn't available. - -### Configure a Firebase-hosted model source - -If you hosted your model with Firebase, register a `CloudModelSource` object, specifying the name you assigned the model when you uploaded it, and the conditions under which ML Kit should download the model initially and when updates are available: - -```csharp -var conditions = new ModelDownloadConditions (true, true); -var cloudModelSource = new CloudModelSource ("my_cloud_model", true, conditions, conditions); -var registrationSuccessful = ModelManager.SharedInstance.Register (cloudModelSource); -``` - -### Configure a local model source - -If you bundled the model with your app, register a `LocalModelSource` object, specifying the filename of the TensorFlow Lite model and assigning the model a name you will use in the next step: - -```csharp -var modelPath = NSBundle.MainBundle.PathForResource ("my_model", "tflite"); - -if (modelPath == null) - return; - -var localModelSource = new LocalModelSource ("my_local_model", modelPath); -var registrationSuccessful = ModelManager.SharedInstance.Register (localModelSource); -``` - -### Create an interpreter from your model sources - -After you configure your model sources, create a `ModelOptions` object with the Cloud source, the local source, or both, and use it to get an instance of `ModelInterpreter`. If you only have one source, specify `null` for the source type you don't use: - -```csharp -var options = new ModelOptions ("my_cloud_model", "my_local_model"); -var interpreter = ModelInterpreter.Create (options); -``` - -## Specify the model's input and output - -Next, configure the model interpreter's input and output formats. - -A TensorFlow Lite model takes as input and produces as output one or more multidimensional arrays. These arrays contain either `byte`, `int`, `long`, or `float` values. You must configure ML Kit with the number and dimensions ("shape") of the arrays your model uses. - -If you don't know the shape and data type of your model's input and output, you can use the TensorFlow Lite Python interpreter to inspect your model. For example: - -```python -import tensorflow as tf - -interpreter = tf.lite.Interpreter(model_path="my_model.tflite") -interpreter.allocate_tensors() - -# Print input shape and type -print(interpreter.get_input_details()[0]['shape']) # Example: [1 224 224 3] -print(interpreter.get_input_details()[0]['dtype']) # Example: - -# Print output shape and type -print(interpreter.get_output_details()[0]['shape']) # Example: [1 1000] -print(interpreter.get_output_details()[0]['dtype']) # Example: -``` - -After you determine the format of your model's input and output, configure your app's model interpreter by creating a `ModelInputOutputOptions` object. - -For example, a floating-point image classification model might take as input an _**N**x224x224x3_ array of `float` values, representing a batch of **N** _224x224_ three-channel (RGB) images, and produce as output a list of 1000 `float` values, each representing the probability the image is a member of one of the 1000 categories the model predicts. - -For such a model, you would configure the model interpreter's input and output as shown below: - -```csharp -var ioOptions = new ModelInputOutputOptions (); - -ioOptions.SetInputFormat (0, ModelElementType.Float32, new nuint[] { 1, 224, 224, 3 }, out NSError inputError); -if (inputError != null) { return; } - -ioOptions.SetOutputFormat (0, ModelElementType.Float32, new nuint [] { 1, 1000 }, out NSError outputError); -if (outputError != null) { return; } -``` - -## Perform inference on input data - -Finally, to perform inference using the model, get your input data, perform any transformations on the data that might be necessary for your model, and build a `NSData` object that contains the data: - -```csharp -var inputData = new NSMutableData (0); - -// Prepare your input data - -var modelInputs = new ModelInputs (); -modelInputs.AddInput (inputData, out NSError error); - -if (error != null) { return; } -``` - -After you prepare your model input, pass the input and input/output options to your `ModelInterpreter`'s `Run` method. - -```csharp -interpreter.Run (modelInputs, ioOptions, HandleModelInterpreterRunCallback); - -void HandleModelInterpreterRunCallback (ModelOutputs outputs, NSError error) -{ - if (error != null || outputs == null) { - return; - } - - // Process outputs -} - -// or use async / await - -try { - ModelOutputs outputs = await interpreter.RunAsync (modelInputs, ioOptions); - - if (outputs == null) { - return; - } - - // Process outputs -} catch (NSErrorException ex) { - -} -``` - -You can get the output by calling the `GetOutput` method of the object that is returned. For example: - -```csharp -// Get first and only output of inference with a batch size of 1 -var output = outputs.GetOutput (0, out NSError outputError) as NSArray; -var probabilities = output.GetItem> (0); -``` - -How you use the output depends on the model you are using. - -## Appendix: Model security - -Regardless of how you make your TensorFlow Lite models available to ML Kit, ML Kit stores them in the standard serialized protobuf format in local storage. - -In theory, this means that anybody can copy your model. However, in practice, most models are so application-specific and obfuscated by optimizations that the risk is similar to that of competitors disassembling and reusing your code. Nevertheless, you should be aware of this risk before you use a custom model in your app. - -# Use a custom TensorFlow Lite build - -If you're an experienced ML developer and the pre-built TensorFlow Lite library doesn't meet your needs, you can use a custom [TensorFlow Lite][5] build with ML Kit. For example, you may want to add custom ops. - -## Prerequisites - -* A working [TensorFlow Lite][6] build environment -* A checkout of TensorFlow Lite 1.10.1 - -You can check out the correct version using Git: - -``` -$ git checkout -b work -$ git reset --hard tflite-v1.10.1 -$ git cherry-pick 4dcfddc5d12018a5a0fdca652b9221ed95e9eb23 -``` - -## Building the Tensorflow Lite library - -1. Build Tensorflow Lite (with your modifications) following the [standard instructions][7] -2. Build the framework: - - ``` - $ tensorflow/lite/lib_package/create_ios_frameworks.sh - ``` - -The generated framework can be found at `tensorflow/lite/gen/ios_frameworks/tensorflow_lite.framework.zip` - -> ![note_icon] **_Note:_** _There have been [build issues reported][8] with Xcode 9.3_ - -## Add your custom TensorFlow Lite framework - -To be able to use your TensorFlow Lite framework, the framework must be copied to TensorFlow Lite Xamarin Build Download cache folder, to do so, follow these steps: - -1. Unzip the tensorflow_lite.framework.zip file generated above -2. Copy the unzipped tensorflow_lite.framework to the TensorFlow Lite Xamarin Build Download cache folder - - * Mac: `~/Library/Caches/XamarinBuildDownload/TnsrFlwLt-1.10.1/Frameworks` - * Windows: `%LOCALAPPDATA%\XamarinBuildDownloadCache\TnsrFlwLt-1.10.1\Frameworks` - - > ![note_icon] _**Note:**_ _If you cannot find the folder, please, open Visual Studio and build your project so Xamarin Build Download can create the TensorFlow Lite cache folder. The `1.10.1` version can vary._ - -3. Erase your `bin` and `obj` folders of your project and build again on Visual Studio - -If you want to use the default TensorFlow Lite framework again, just erase everything that start with `TnsrFlwLt-1.10.1` in the Xamarin Build Download cache folder, erase the `bin` and `obj` folders and build again your project on Visual Studio. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/ml-kit/ios/use-custom-models) to see original Firebase documentation._ - -[1]: https://firebase.google.com/console/ -[2]: http://support.google.com/firebase/answer/7015592 -[3]: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/toco -[4]: https://firebase.google.com/docs/ml-kit/ios/use-custom-models#model_security -[5]: https://www.tensorflow.org/mobile/tflite/ -[6]: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/README.md#building-tensorflow-lite-and-the-demo-app-from-source -[7]: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/ios.md -[8]: https://github.com/tensorflow/tensorflow/issues/18356 -[note_icon]: https://cdn3.iconfinder.com/data/icons/UltimateGnome/22x22/apps/gnome-app-install-star.png -[warning_icon]: https://cdn2.iconfinder.com/data/icons/freecns-cumulus/32/519791-101_Warning-20.png diff --git a/docs/Firebase/MLKit.NaturalLanguage/Details.md b/docs/Firebase/MLKit.NaturalLanguage/Details.md deleted file mode 100755 index 4b93dd714..000000000 --- a/docs/Firebase/MLKit.NaturalLanguage/Details.md +++ /dev/null @@ -1,86 +0,0 @@ -# Language Identification - -With ML Kit's on-device language identification API, you can determine the language of a string of text. - -Language identification can be useful when working with user-provided text, which often doesn't come with any language information. - -## Key capabilities - -| | | -|-:|-| -| **Broad language support** | Identifies over a hundred different languages. See the [complete list][Language-1]. | -| **Romanized text support** | Identifies Arabic, Bulgarian, Greek, Hindi, Japanese, Russian, and Chinese text in both native and romanized script. | - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/ml-kit/identify-languages) to see original Firebase documentation._ - -[Language-1]: https://firebase.google.com/docs/ml-kit/langid-support -[available_icon]: https://cdn3.iconfinder.com/data/icons/flat-actions-icons-9/512/Tick_Mark-24.png - ---- - -# Translation - -With ML Kit's on-device translation API, you can dynamically translate text between 59 languages. - -## Key capabilities - -| | | -|-:|-| -| **Broad language support** | Translate between 59 different languages. See the [complete list][Translation-1]. | -| **Proven translation models** | Powered by the same models used by the Google Translate app's offline mode. | -| **Dynamic model management** | Keep on-device storage requirements low by dynamically downloading and managing language packs. | -| **Runs on the device** | Translations are performed quickly, and don't require you to send users' text to a remote server. | - -## Limitations - -On-device translation is intended for casual and simple translations, and the quality of translations depends on the specific languages being translated from and to. As such, you should evaluate the quality of the translations for your specific use case. If you require higher fidelity, try the [Cloud Translation API][Translation-2]. - -Also, ML Kit's translation models are trained to translate to and from English. When you translate between non-English languages, English is used as an intermediate translation, which can affect quality. - -## Usage guidelines - -Refer to [Usage Guidelines for ML Kit On-device Translation][Translation-3] for important guidelines and restrictions on usage of this API. This document covers requirements around doing attribution in your app when translating text. - -## Providing feedback - -Due to the complexity of natural language processing, the translations provided might not be appropriate for all contexts or audiences. If you encounter inappropriate translations, reach out to [Firebase support][Translation-4]. Your feedback helps to continue to improve the models, and also allows us to disable inappropriate translations. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/ml-kit/translation) to see original Firebase documentation._ - -[Translation-1]: https://firebase.google.com/docs/ml-kit/translation-language-support -[Translation-2]: https://cloud.google.com/translate/ -[Translation-3]: https://firebase.google.com/docs/ml-kit/translation-terms -[Translation-4]: https://firebase.google.com/support - ---- - -# Smart Reply - -With ML Kit's Smart Reply API, you can automatically generate relevant replies to messages. Smart Reply helps your users respond to messages quickly, and makes it easier to reply to messages on devices with limited input capabilities. - -## Key capabilities - -| | | -|-:|-| -| **Generates contextually-relevant suggestions** | The Smart Reply model generates reply suggestions based on the full context of a conversation, and not just a single message, resulting in suggestions that are more helpful to your users. | -| **Runs on the device** | The on-device model generates replies quickly, and doesn't require you to send users' messages to a remote server. | - -## Limitations - -* Smart Reply is intended for casual conversations in consumer apps. Reply suggestions might not be appropriate for other contexts or audiences. -* Currently, only English is supported. The model automatically detects if a different language is used and if so, will not provide suggestions. - -## How the model works - -* The model uses up to 10 of the most recent messages from a conversation history to generate reply suggestions. -* It detects the language of the conversation and only attempts to provide responses when the language is determined to be English. -* Next, the model compares the messages against a list of sensitive topics and won’t provide suggestions when it detects a sensitive topic. -* If the language is determined to be English and no sensitive topics are detected, the model provides up to three suggested responses. The number of responses depends on how many meet a sufficient level of confidence based on the input to the model. - -## Providing feedback - -Due to the complexity of natural language processing, the suggestions provided by the model might not be appropriate for all contexts or audiences. If you encounter inappropriate reply suggestions, reach out to [Firebase support][Smart-Reply-1]. Your feedback helps to continue to improve the model and sensitive topic filter. - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/ml-kit/generate-smart-replies) to see original Firebase documentation._ - -[Smart-Reply-1]: https://firebase.google.com/support diff --git a/docs/Firebase/MLKit.NaturalLanguage/GettingStarted.md b/docs/Firebase/MLKit.NaturalLanguage/GettingStarted.md deleted file mode 100755 index 3cc63a394..000000000 --- a/docs/Firebase/MLKit.NaturalLanguage/GettingStarted.md +++ /dev/null @@ -1,245 +0,0 @@ -# Get Started with Firebase MLKit for iOS - -Use machine learning in your apps to solve real-world problems. - -ML Kit is a mobile SDK that brings Google's machine learning expertise to Android and iOS apps in a powerful yet easy-to-use package. Whether you're new or experienced in machine learning, you can implement the functionality you need in just a few lines of code. There's no need to have deep knowledge of neural networks or model optimization to get started. On the other hand, if you are an experienced ML developer, ML Kit provides convenient APIs that help you use your custom TensorFlow Lite models in your mobile apps. - -## Table of Content - -- [Get Started with Firebase MLKit for iOS](#get-started-with-firebase-mlkit-for-ios) - - [Table of Content](#table-of-content) - - [Add Firebase to your app](#add-firebase-to-your-app) - - [Configure MLKit Natural Language in your app](#configure-mlkit-natural-language-in-your-app) -- [Identify the language of text with ML Kit on iOS](#identify-the-language-of-text-with-ml-kit-on-ios) - - [Identify the language of a string](#identify-the-language-of-a-string) - - [Get the possible languages of a string](#get-the-possible-languages-of-a-string) -- [Translate text with ML Kit on iOS](#translate-text-with-ml-kit-on-ios) - - [Translate a string of text](#translate-a-string-of-text) - - [Explicitly manage translation models](#explicitly-manage-translation-models) - -## Add Firebase to your app - -1. Create a Firebase project in the [Firebase console][1], if you don't already have one. If you already have an existing Google project associated with your mobile app, click **Import Google Project**. Otherwise, click **Create New Project**. -2. Click **Add Firebase to your iOS app** and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just [download the config file][2]. -3. When prompted, enter your app's bundle ID. It's important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project. -4. At the end, you'll download a `GoogleService-Info.plist` file. You can [download this file][2] again at any time. - -## Configure MLKit Natural Language in your app - -Once you have your `GoogleService-Info.plist` file downloaded in your computer, do the following steps in Visual Studio: - -1. Add `GoogleService-Info.plist` file to your app project. -2. Set `GoogleService-Info.plist` **build action** behaviour to `Bundle Resource` by Right clicking/Build Action. -3. Add the following line of code somewhere in your app, typically in your AppDelegate's `FinishedLaunching` method (don't forget to import `Firebase.Core` namespace): - -```csharp -App.Configure (); -``` - -[1]: https://firebase.google.com/console/ -[2]: http://support.google.com/firebase/answer/7015592 - ---- - -# Identify the language of text with ML Kit on iOS - -You can use ML Kit to identify the language of a string of text. You can get the string's most likely language or get confidence scores for all of the string's possible languages. - -ML Kit recognizes text in 103 different languages in their native scripts. In addition, romanized text can be recognized for Arabic, Bulgarian, Chinese, Greek, Hindi, Japanese, and Russian. - -## Identify the language of a string - -To identify the language of a string, get an instance of `LanguageIdentification`, and then pass the string to the `IdentifyLanguage` method: - -```csharp -var languageId = NaturalLanguageApi.DefaultInstance.GetLanguageIdentification (); - -languageId.IdentifyLanguage (text, IdentifyLanguageCallbackHandler); - -void IdentifyLanguageCallbackHandler (string languageCode, NSError error) -{ - if (error != null) { - Console.WriteLine ($"Failed with error: {error.LocalizedDescription}"); - return; - } - - if (languageCode == "und") { - Console.WriteLine ("No language was identified"); - return; - } - - Console.WriteLine ($"Identified Language: {languageCode}"); -} - -// async / await version - -try { - var languageCode = await languageId.IdentifyLanguageAsync (text); - - if (languageCode == "und") { - Console.WriteLine ("No language was identified"); - return; - } - - Console.WriteLine ($"Identified Language: {languageCode}"); -} catch (NSErrorException ex) { - Console.WriteLine ($"Failed with error: {ex.Error.LocalizedDescription}"); -} -``` - -If the call succeeds, a [BCP-47 language][Language-1] code is passed to the completion handler, indicating the language of the text. See the [complete list of supported languages][Language-2]. If no language could be confidently detected, the code `und` (undetermined) is passed. - -By default, ML Kit returns a non-`und` value only when it identifies the language with a confidence value of at least 0.5. You can change this threshold by passing a `LanguageIdentificationOptions` object to `GetLanguageIdentification (LanguageIdentificationOptions)`: - -```csharp -var options = new LanguageIdentificationOptions (.4f); -var languageId = NaturalLanguageApi.DefaultInstance.GetLanguageIdentification (options); -``` - -## Get the possible languages of a string - -To get the confidence values of a string's most likely languages, get an instance of `LanguageIdentification`, and then pass the string to the `IdentifyPossibleLanguages` method: - -```csharp -var languageId = NaturalLanguageApi.DefaultInstance.GetLanguageIdentification (); - -languageId.IdentifyPossibleLanguages (text, IdentifyPossibleLanguagesCallbackHandler); - -void IdentifyPossibleLanguagesCallbackHandler (IdentifiedLanguage [] identifiedLanguages, NSError error) -{ - if (error != null) { - Console.WriteLine ($"Failed with error: {error.LocalizedDescription}"); - return; - } - - if (identifiedLanguages.Length > 0 && identifiedLanguages [0].LanguageCode == "und") { - Console.WriteLine ("No language was identified"); - return; - } - - foreach (var identifiedLanguage in identifiedLanguages) - Console.WriteLine ($"({identifiedLanguage.LanguageCode}, {identifiedLanguage.Confidence:.##})"); -} - -// async / await version - -try { - var identifiedLanguages = await languageId.IdentifyPossibleLanguagesAsync (text); - - if (identifiedLanguages.Length > 0 && identifiedLanguages [0].LanguageCode == "und") { - Console.WriteLine ("No language was identified"); - return; - } - - foreach (var identifiedLanguage in identifiedLanguages) - Console.WriteLine ($"({identifiedLanguage.LanguageCode}, {identifiedLanguage.Confidence:.##})"); -} catch (NSErrorException ex) { - Console.WriteLine ($"Failed with error: {ex.Error.LocalizedDescription}"); -} -``` - -If the call succeeds, a list of `IdentifiedLanguage` objects is passed to the continuation handler. From each object, you can get the language's BCP-47 code and the confidence that the string is in that language. See the [complete list of supported languages][Language-2]. Note that these values indicate the confidence that the entire string is in the given language; ML Kit doesn't identify multiple languages in a single string. - -By default, ML Kit returns only languages with confidence values of at least 0.01. You can change this threshold by passing a `LanguageIdentificationOptions` object to `GetLanguageIdentification (LanguageIdentificationOptions)`: - -```csharp -var options = new LanguageIdentificationOptions (.4f); -var languageId = NaturalLanguageApi.DefaultInstance.GetLanguageIdentification (options); -``` - -If no language meets this threshold, the list will have one item, with the value `und`. - -[Language-1]: https://en.wikipedia.org/wiki/IETF_language_tag -[Language-2]: https://firebase.google.com/docs/ml-kit/langid-support - ---- - -# Translate text with ML Kit on iOS - -You can use ML Kit to translate text between languages. ML Kit currently supports translation between [59 languages][Translate-1]. - -## Translate a string of text - -To translate a string between two languages: - -1. Create a `Translator` object, configuring it with the source and target languages: - - ```csharp - // Create an English-German translator: - var options = new TranslatorOptions (TranslateLanguage.En, TranslateLanguage.De); - var englishGermanTranslator = NaturalLanguageApi.DefaultInstance.GetTranslator (options); - ``` - - If you don't know the language of the input text, you can use the [language identification API][Translate-2] first. (But be sure you don't keep too many language models on the device at once.) - -2. Make sure the required translation model has been downloaded to the device. Don't call `TranslateText` until you know the model is available: - - ```csharp - var conditions = new ModelDownloadConditions (false, true); - englishGermanTranslator.DownloadModelIfNeeded (conditions, TranslatorDownloadModelIfNeededCallbackHandler); - - void TranslatorDownloadModelIfNeededCallbackHandler (NSError error) - { - if (error != null) - return; - - // Model downloaded successfully. Okay to start translating. - - } - - // async / await version - - try { - await englishGermanTranslator.DownloadModelIfNeededAsync (conditions); - - // Model downloaded successfully. Okay to start translating. - } catch (NSErrorException ex) { - // Handle error - } - ``` - - Language models are around 30MB, so don't download them unnecessarily, and only download them using WiFi, unless the user has specified otherwise. You should also delete unneeded models. See [Explicitly manage translation models][Translate-3]. - -3. After you confirm the model has been downloaded, pass a string of text in the source language to `TranslateText`: - - ```csharp - englishGermanTranslator.TranslateText (text, TranslatorCallbackHandler); - - void TranslatorCallbackHandler (string result, NSError error) - { - if (error != null) - return; - - // Translation succeeded. - } - - // async / await version - - try { - var result = await englishGermanTranslator.TranslateTextAsync (text); - - // Translation succeeded. - } catch (NSErrorException ex) { - // Handle error - } - ``` - - ML Kit translates the text to the target language you configured and passes the translated text to the completion handler. - -## Explicitly manage translation models - -When you use the translation API as described above, ML Kit automatically downloads language-specific translation models to the device as required. You can also explicitly manage the translation models you want available on the device by using ML Kit's translation model management API. This can be useful if you want to download models ahead of time, or delete unneeded models from the device. - -To get the translation models stored on the device: - -```csharp -var -``` - -[Translate-1]: https://firebase.google.com/docs/ml-kit/translation-language-support -[Translate-2]: #identify-the-language-of-text-with-ml-kit-on-ios -[Translate-3]: #explicitly-manage-translation-models - -[note_icon]: https://cdn3.iconfinder.com/data/icons/UltimateGnome/22x22/apps/gnome-app-install-star.png -[warning_icon]: https://cdn2.iconfinder.com/data/icons/freecns-cumulus/32/519791-101_Warning-20.png -[available_icon]: https://cdn3.iconfinder.com/data/icons/flat-actions-icons-9/512/Tick_Mark-24.png diff --git a/docs/Firebase/MLKit/Details.md b/docs/Firebase/MLKit/Details.md deleted file mode 100755 index 8be391b30..000000000 --- a/docs/Firebase/MLKit/Details.md +++ /dev/null @@ -1,31 +0,0 @@ -Use machine learning in your apps to solve real-world problems. - -ML Kit is a mobile SDK that brings Google's machine learning expertise to Android and iOS apps in a powerful yet easy-to-use package. Whether you're new or experienced in machine learning, you can implement the functionality you need in just a few lines of code. There's no need to have deep knowledge of neural networks or model optimization to get started. On the other hand, if you are an experienced ML developer, ML Kit provides convenient APIs that help you use your custom TensorFlow Lite models in your mobile apps. - -## Key capabilities - -| | | -|-:|-| -| **Production-ready for common use cases:** | ML Kit comes with a set of ready-to-use APIs for common mobile use cases: recognizing text, detecting faces, identifying landmarks, scanning barcodes, and labeling images. Simply pass in data to the ML Kit library and it gives you the information you need. | -| **On-device or in the cloud:** | ML Kit’s selection of APIs run on-device or in the cloud. Our on-device APIs can process your data quickly and work even when there’s no network connection. Our cloud-based APIs, on the other hand, leverage the power of Google Cloud Platform's machine learning technology to give you an even higher level of accuracy. | -| **Deploy custom models:** | If ML Kit's APIs don't cover your use cases, you can always bring your own existing TensorFlow Lite models. Just upload your model to Firebase, and we'll take care of hosting and serving it to your app. ML Kit acts as an API layer to your custom model, making it simpler to run and use. | - -## How does it work? - -ML Kit makes it easy to apply ML techniques in your apps by bringing Google's ML technologies, such as the Google Cloud Vision API, TensorFlow Lite, and the Android Neural Networks API together in a single SDK. Whether you need the power of cloud-based processing, the real-time capabilities of mobile-optimized on-device models, or the flexibility of custom TensorFlow Lite models, ML Kit makes it possible with just a few lines of code. - -### What features are available on device or in the cloud? - -| Feature | On-device | Cloud | -|------------------------|:-----------------:|:-----------------:| -| Text recognition | ![available_icon] | ![available_icon] | -| Face detection | ![available_icon] | | -| Barcode scanning | ![available_icon] | | -| Image labeling | ![available_icon] | ![available_icon] | -| Landmark recognition | | ![available_icon] | -| Custom model inference | ![available_icon] | | - - -_Portions of this page are modifications based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in the [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). Click [here](https://firebase.google.com/docs/analytics/) to see original Firebase documentation._ - -[available_icon]: https://cdn3.iconfinder.com/data/icons/flat-actions-icons-9/512/Tick_Mark-24.png \ No newline at end of file diff --git a/docs/Firebase/MLKit/GettingStarted.md b/docs/Firebase/MLKit/GettingStarted.md deleted file mode 100755 index f674c9f9f..000000000 --- a/docs/Firebase/MLKit/GettingStarted.md +++ /dev/null @@ -1,1297 +0,0 @@ -# Get Started with Firebase MLKit for iOS - -Use machine learning in your apps to solve real-world problems. - -ML Kit is a mobile SDK that brings Google's machine learning expertise to Android and iOS apps in a powerful yet easy-to-use package. Whether you're new or experienced in machine learning, you can implement the functionality you need in just a few lines of code. There's no need to have deep knowledge of neural networks or model optimization to get started. On the other hand, if you are an experienced ML developer, ML Kit provides convenient APIs that help you use your custom TensorFlow Lite models in your mobile apps. - -## Table of Content - -- [Get Started with Firebase MLKit for iOS](#get-started-with-firebase-mlkit-for-ios) - - [Table of Content](#table-of-content) - - [Add Firebase to your app](#add-firebase-to-your-app) - - [Configure MLKit in your app](#configure-mlkit-in-your-app) -- [Text Recognition](#text-recognition) - - [Choose between on-device and Cloud APIs](#choose-between-on-device-and-cloud-apis) -- [Recognize Text in Images with ML Kit on iOS](#recognize-text-in-images-with-ml-kit-on-ios) - - [Input image guidelines](#input-image-guidelines) - - [Recognize text in images](#recognize-text-in-images) - - [1. Run the text recognizer](#1-run-the-text-recognizer) - - [2. Extract text from blocks of recognized text](#2-extract-text-from-blocks-of-recognized-text) - - [Tips to improve real-time performance](#tips-to-improve-real-time-performance) - - [Recognize text in images of documents](#recognize-text-in-images-of-documents) - - [1. Run the text recognizer](#1-run-the-text-recognizer-1) - - [2. Extract text from blocks of recognized text](#2-extract-text-from-blocks-of-recognized-text-1) -- [Face Detection](#face-detection) - - [Key capabilities](#key-capabilities) -- [Face Detection Concepts Overview](#face-detection-concepts-overview) -- [Detect Faces with ML Kit on iOS](#detect-faces-with-ml-kit-on-ios) - - [Input image guidelines](#input-image-guidelines-1) - - [1. Configure the face detector](#1-configure-the-face-detector) - - [2. Run the face detector](#2-run-the-face-detector) - - [3. Get information about detected faces](#3-get-information-about-detected-faces) -- [Barcode Scanning](#barcode-scanning) - - [Key capabilities](#key-capabilities-1) -- [Scan Barcodes with ML Kit on iOS](#scan-barcodes-with-ml-kit-on-ios) - - [Input image guidelines](#input-image-guidelines-2) - - [1. Configure the barcode detector](#1-configure-the-barcode-detector) - - [2. Run the barcode detector](#2-run-the-barcode-detector) - - [3. Get information from barcodes](#3-get-information-from-barcodes) - - [Tips to improve real-time performance](#tips-to-improve-real-time-performance-1) -- [Image Labeling](#image-labeling) - - [Choose between on-device and Cloud APIs](#choose-between-on-device-and-cloud-apis-1) - - [Example on-device labels](#example-on-device-labels) - - [Example cloud labels](#example-cloud-labels) - - [Google Knowledge Graph entity IDs](#google-knowledge-graph-entity-ids) -- [Label Images with ML Kit on iOS](#label-images-with-ml-kit-on-ios) - - [On-device image labeling](#on-device-image-labeling) - - [1. Configure the image labeler](#1-configure-the-image-labeler) - - [2. Run the image labeler](#2-run-the-image-labeler) - - [3. Get information about labeled objects](#3-get-information-about-labeled-objects) - - [Tips to improve real-time performance](#tips-to-improve-real-time-performance-2) - - [Cloud image labeling](#cloud-image-labeling) - - [1. Configure the image labeler](#1-configure-the-image-labeler-1) - - [2. Run the image labeler](#2-run-the-image-labeler-1) - - [3. Get information about labeled objects](#3-get-information-about-labeled-objects-1) -- [Landmark Recognition](#landmark-recognition) - - [Key capabilities](#key-capabilities-2) -- [Recognize Landmarks with ML Kit on iOS](#recognize-landmarks-with-ml-kit-on-ios) - - [Configure the landmark detector](#configure-the-landmark-detector) - - [Run the landmark detector](#run-the-landmark-detector) - - [Get information about the recognized landmarks](#get-information-about-the-recognized-landmarks) -- [Protect your ML Kit iOS app's Cloud credentials](#protect-your-ml-kit-ios-apps-cloud-credentials) - -## Add Firebase to your app - -1. Create a Firebase project in the [Firebase console][10], if you don't already have one. If you already have an existing Google project associated with your mobile app, click **Import Google Project**. Otherwise, click **Create New Project**. -2. Click **Add Firebase to your iOS app** and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just [download the config file][11]. -3. When prompted, enter your app's bundle ID. It's important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project. -4. At the end, you'll download a `GoogleService-Info.plist` file. You can [download this file][11] again at any time. - -If you want to use the Cloud-based model, and you have not already enabled the Cloud-based APIs for your project, do so now: - -1. Open the ML Kit APIs page of the Firebase console. -2. If you have not already upgraded your project to a Blaze plan, click **Upgrade** to do so. (You will be prompted to upgrade only if your project isn't on the Blaze plan.) - - Only Blaze-level projects can use Cloud-based APIs. - -3. If Cloud-based APIs aren't already enabled, click **Enable Cloud-based APIs.** - -> ![note_icon] *Before you deploy to production an app that uses a Cloud API, you should take some additional steps to [prevent and mitigate the effect of unauthorized API access.][4]* - -If you want to use only the on-device model, you can skip these steps. - -## Configure MLKit in your app - -Once you have your `GoogleService-Info.plist` file downloaded in your computer, do the following steps in Visual Studio: - -1. Add `GoogleService-Info.plist` file to your app project. -2. Set `GoogleService-Info.plist` **build action** behaviour to `Bundle Resource` by Right clicking/Build Action. -3. Add the following line of code somewhere in your app, typically in your AppDelegate's `FinishedLaunching` method (don't forget to import `Firebase.Core` namespace): - -```csharp -App.Configure (); -``` - ---- - -# Text Recognition - -With ML Kit's text recognition APIs, you can recognize text in any Latin-based language (and more, with Cloud-based text recognition). - -Text recognition can automate tedious data entry for credit cards, receipts, and business cards. With the Cloud-based API, you can also extract text from documents, which you can use to increase accessibility or translate documents. Apps can even keep track of real-world objects, such as by reading the numbers on trains. - -## Choose between on-device and Cloud APIs - -| | On-device | Cloud | -|--|-----------|-------| -| **Pricing** | Free | Free for first 1000 uses of this feature per month: see [Pricing][1] | -| **Ideal use cases** | Real-time processing—ideal for a camera or video feed
Recognizing sparse text in images | High-accuracy text recognition
Recognizing sparse text in images
Recognizing densely-spaced text in documents

See the [Cloud Vision API demo][2] | -| **Language support** | Recognizes Latin characters | Recognizes and identifies a broad range of languages and special characters | - -# Recognize Text in Images with ML Kit on iOS - -You can use ML Kit to recognize text in images. ML Kit has both a general-purpose API suitable for recognizing text in images, such as the text of a street sign, and an API optimized for recognizing the text of documents. The general-purpose API has both on-device and cloud-based models. Document text recognition is available only as a cloud-based model. See the [overview][3] for a comparison of the cloud and on-device models. - -## Input image guidelines - -* For ML Kit to accurately recognize text, input images must contain text that is represented by sufficient pixel data. Ideally, for Latin text, each character should be at least 16x16 pixels. For Chinese, Japanese, and Korean text (only supported by the cloud-based APIs), each character should be 24x24 pixels. For all languages, there is generally no accuracy benefit for characters to be larger than 24x24 pixels. - - So, for example, a 640x480 image might work well to scan a business card that occupies the full width of the image. To scan a document printed on letter-sized paper, a 720x1280 pixel image might be required. - -* Poor image focus can hurt text recognition accuracy. If you aren't getting acceptable results, try asking the user to recapture the image. -* If you are recognizing text in a real-time application, you might also want to consider the overall dimensions of the input images. Smaller images can be processed faster, so to reduce latency, capture images at lower resolutions (keeping in mind the above accuracy requirements) and ensure that the text occupies as much of the image as possible. - -## Recognize text in images - -To recognize text in an image using either an on-device or cloud-based model, run the text recognizer as described below. - -### 1. Run the text recognizer - -Pass the image as a `UIImage` or a `CMSampleBuffer` to the `VisionTextRecognizer`'s `ProcessImage` method: - -1. Get an instance of `VisionTextRecognizer` by calling either `GetOnDeviceTextRecognizer` or `GetCloudTextRecognizer`: - - ```csharp - var vision = VisionApi.Create (); - var textRecognizer = vision.GetOnDeviceTextRecognizer (); - ``` - - To use the cloud model: - - > ![note_icon] _Use of ML Kit to access Cloud ML functionality is subject to the [Google Cloud Platform License Agreement][5] and [Service Specific Terms][6], and billed accordingly. For billing information, see the Firebase [Pricing][1] page._ - - ```csharp - var vision = VisionApi.Create (); - var textRecognizer = vision.GetOnDeviceTextRecognizer (); - - // Or, to provide language hints to assist with language detection: - // See https://cloud.google.com/vision/docs/languages for supported languages - var options = new VisionCloudTextRecognizerOptions { LanguageHints = new []{ "es" } }; - var textRecognizer = vision.GetCloudTextRecognizer (options); - ``` - -2. Create a `VisionImage` object using a `UIImage` or a `CMSampleBuffer`. - - To use a `UIImage`: - - 1. If necessary, rotate the image so that its `ImageOrientation` property is `Up`. - 2. Create a `VisionImage` object using the correctly-rotated `UIImage`. Do not specify any rotation metadata—the default value, `TopLeft`, must be used. - - ```csharp - var image = new VisionImage (anImage); - ``` - - To use a `CMSampleBuffer`: - - 1. Create a `VisionImageMetadata` object that specifies the orientation of the image data contained in the `CMSampleBuffer` buffer. - - For example, if you are using image data captured from the device's back-facing camera: - - ```csharp - var metadata = new VisionImageMetadata (); - - // Using back-facing camera - var devicePosition = AVCaptureDevicePosition.Back; - - var deviceOrientation = UIDevice.CurrentDevice.Orientation; - - switch (deviceOrientation) { - case UIDeviceOrientation.Portrait: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.LeftTop : VisionDetectorImageOrientation.RightTop; - break; - case UIDeviceOrientation.LandscapeLeft: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.BottomLeft : VisionDetectorImageOrientation.TopLeft; - break; - case UIDeviceOrientation.PortraitUpsideDown: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.RightBottom : VisionDetectorImageOrientation.LeftBottom; - break; - case UIDeviceOrientation.LandscapeRight: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.TopRight : VisionDetectorImageOrientation.BottomRight; - break; - case UIDeviceOrientation.FaceUp: - case UIDeviceOrientation.FaceDown: - case UIDeviceOrientation.Unknown: - metadata.Orientation = VisionDetectorImageOrientation.LeftTop; - break; - } - ``` - - 2. Create a `VisionImage` object using the `CMSampleBuffer` object and the rotation metadata: - - ```csharp - var image = new VisionImage (buffer); - image.Metadata = metadata; - ``` - -3. Then, pass the image to the `ProcessImage` method: - - ```csharp - textRecognizer.ProcessImage (image, HandleVisionTextRecognitionCallback); - - void HandleVisionTextRecognitionCallback (VisionText text, NSError error) - { - Console.WriteLine (error?.Description ?? text?.Text); - } - - // or using async / await - - try { - var text = await textRecognizer.ProcessImageAsync (image); - Console.WriteLine (text.Text); - } catch (NSErrorException ex) { - Console.WriteLine (ex.Error.Description); - } - ``` - -### 2. Extract text from blocks of recognized text - -If the text recognition operation succeeds, it will return a `VisionText` object. A `VisionText` object contains the full text recognized in the image and zero or more `VisionTextBlock` objects. - -Each `VisionTextBlock` represents a rectangular block of text, which contain zero or more `VisionTextLine` objects. - -Each `VisionTextLine` object contains zero or more `VisionTextElement` objects, which represent words and word-like entities (dates, numbers, and so on). - -For each `VisionTextBlock`, `VisionTextLine`, and `VisionTextElement` object, you can get the text recognized in the region and the bounding coordinates of the region. - -For example: - -```csharp -foreach (var block in text.Blocks) { - var blockText = block.Text; - var blockConfidence = block.Confidence.Value; - var blockLanguage = block.RecognizedLanguages; - var blockCornerPoints = block.CornerPoints; - var blockFrame = block.Frame; - - foreach (var line in block.Lines) { - var lineText = line.Text; - var lineConfidence = line.Confidence.Value; - var lineLanguage = line.RecognizedLanguages; - var lineCornerPoints = line.CornerPoints; - var lineFrame = line.Frame; - - foreach (var element in line.Elements) { - var elementText = element.Text; - var elementConfidence = element.Confidence.Value; - var elementLanguage = element.RecognizedLanguages; - var elementCornerPoints = element.CornerPoints; - var elementFrame = element.Frame; - } - } -} -``` - -### Tips to improve real-time performance - -If you want use the on-device model to recognize text in a real-time application, follow these guidelines to achieve the best framerates: - -* Throttle calls to the text recognizer. If a new video frame becomes available while the text recognizer is running, drop the frame. -* Consider capturing images at a lower resolution. However, also keep in mind this API's image dimension requirements. - -## Recognize text in images of documents - -To recognize the text of a document, configure and run the cloud-based document text recognizer as described below. - -> ![note_icon] _Use of ML Kit to access Cloud ML functionality is subject to the [Google Cloud Platform License Agreement][5] and [Service Specific Terms][6], and billed accordingly. For billing information, see the Firebase [Pricing][1] page._ - -The document text recognition API, described below, provides an interface that is intended to be more convenient for working with images of documents. However, if you prefer the interface provided by the sparse text API, you can use it instead to scan documents by configuring the cloud text recognizer to use the dense text model. - -To use the document text recognition API: - -### 1. Run the text recognizer - -Pass the image as a `UIImage` or a `CMSampleBuffer` to the `VisionDocumentTextRecognizer`'s `ProcessImage` method: - -1. Get an instance of `VisionDocumentTextRecognizer` by calling `GetCloudDocumentTextRecognizer`: - - ```csharp - var vision = VisionApi.Create (); - var textRecognizer = vision.GetCloudDocumentTextRecognizer (); - - // Or, to provide language hints to assist with language detection: - // See https://cloud.google.com/vision/docs/languages for supported languages - var options = new VisionCloudDocumentTextRecognizerOptions { LanguageHints = new [] { "es" } }; - var textRecognizer = vision.GetCloudDocumentTextRecognizer (options); - ``` - -2. Create a `VisionImage` object using a `UIImage` or a `CMSampleBuffer`. - - To use a `UIImage`: - - 1. If necessary, rotate the image so that its `ImageOrientation` property is `Up`. - 2. Create a `VisionImage` object using the correctly-rotated `UIImage`. Do not specify any rotation metadata—the default value, `TopLeft`, must be used. - - ```csharp - var image = new VisionImage (anImage); - ``` - - To use a `CMSampleBuffer`: - - 1. Create a `VisionImageMetadata` object that specifies the orientation of the image data contained in the `CMSampleBuffer` buffer. - - For example, if you are using image data captured from the device's back-facing camera: - - ```csharp - var metadata = new VisionImageMetadata (); - - // Using back-facing camera - var devicePosition = AVCaptureDevicePosition.Back; - - var deviceOrientation = UIDevice.CurrentDevice.Orientation; - - switch (deviceOrientation) { - case UIDeviceOrientation.Portrait: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.LeftTop : VisionDetectorImageOrientation.RightTop; - break; - case UIDeviceOrientation.LandscapeLeft: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.BottomLeft : VisionDetectorImageOrientation.TopLeft; - break; - case UIDeviceOrientation.PortraitUpsideDown: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.RightBottom : VisionDetectorImageOrientation.LeftBottom; - break; - case UIDeviceOrientation.LandscapeRight: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.TopRight : VisionDetectorImageOrientation.BottomRight; - break; - case UIDeviceOrientation.FaceUp: - case UIDeviceOrientation.FaceDown: - case UIDeviceOrientation.Unknown: - metadata.Orientation = VisionDetectorImageOrientation.LeftTop; - break; - } - ``` - - 2. Create a `VisionImage` object using the `CMSampleBuffer` object and the rotation metadata: - - ```csharp - var image = new VisionImage (buffer); - image.Metadata = metadata; - ``` - -3. Then, pass the image to the `ProcessImage` method: - - ```csharp - textRecognizer.ProcessImage (image, HandleVisionDocumentTextRecognitionCallback); - - void HandleVisionDocumentTextRecognitionCallback (VisionDocumentText text, NSError error) - { - Console.WriteLine (error?.Description ?? text?.Text); - } - - // or using async / await - - try { - var text = await textRecognizer.ProcessImageAsync (image); - Console.WriteLine (text.Text); - } catch (NSErrorException ex) { - Console.WriteLine (ex.Error.Description); - } - ``` - -### 2. Extract text from blocks of recognized text - -If the text recognition operation succeeds, it will return a `VisionDocumentText` object. A `VisionDocumentText` object contains the full text recognized in the image and a hierarchy of objects that reflect the structure of the recognized document: - -* `VisionDocumentTextBlock` -* `VisionDocumentTextParagraph` -* `VisionDocumentTextWord` -* `VisionDocumentTextSymbol` - -For each `VisionDocumentTextBlock`, `VisionDocumentTextParagraph`, `VisionDocumentTextWord`, and `VisionDocumentTextSymbol` object, you can get the text recognized in the region and the bounding coordinates of the region. - -For example: - -```csharp -foreach (var block in text.Blocks) { - var blockText = block.Text; - var blockConfidence = block.Confidence.Value; - var blockLanguage = block.RecognizedLanguages; - var blockRecognizedBreak = block.RecognizedBreak; - var blockFrame = block.Frame; - - foreach (var paragraph in block.Paragraphs) { - var paragraphText = paragraph.Text; - var paragraphConfidence = paragraph.Confidence; - var paragraphLanguage = paragraph.RecognizedLanguages; - var paragraphRecognizedBreak = paragraph.RecognizedBreak; - var paragraphFrame = paragraph.Frame; - - foreach (var word in paragraph.Words) { - var wordText = word.Text; - var wordConfidence = word.Confidence; - var wordLanguage = word.RecognizedLanguages; - var wordRecognizedBreak = word.RecognizedBreak; - var wordFrame = word.Frame; - - foreach (var symbol in word.Symbols) { - var symbolText = symbol.Text; - var symbolConfidence = symbol.Confidence; - var symbolLanguage = symbol.RecognizedLanguages; - var symbolRecognizedBreak = symbol.RecognizedBreak; - var symbolFrame = symbol.Frame; - } - } - } -} -``` - ---- - -# Face Detection - -With ML Kit's face detection API, you can detect faces in an image, identify key facial features, and get the contours of detected faces. - -With face detection, you can get the information you need to perform tasks like embellishing selfies and portraits, or generating avatars from a user's photo. Because ML Kit can perform face detection in real time, you can use it in applications like video chat or games that respond to the player's expressions. - -## Key capabilities - -| | | -|-------|-------| -| **Recognize and locate facial features** | Get the coordinates of the eyes, ears, cheeks, nose, and mouth of every face detected. | -| **Get the contours of facial features** | Get the contours of detected faces and their eyes, eyebrows, lips, and nose. | -| **Recognize facial expressions** | Determine whether a person is smiling or has their eyes closed. | -| **Track faces across video frames** | Get an identifier for each individual person's face that is detected. This identifier is consistent across invocations, so you can, for example, perform image manipulation on a particular person in a video stream. | -| **Process video frames in real time** | Face detection is performed on the device, and is fast enough to be used in real-time applications, such as video manipulation. | - -# Face Detection Concepts Overview - -Face detection is the process of automatically locating human faces in visual media (digital images or video). A face that is detected is reported at a position with an associated size and orientation. Once a face is detected, it can be searched for landmarks such as the eyes and nose. - -To learn more about this, please, read the following [documentation][7]. - -# Detect Faces with ML Kit on iOS - -You can use ML Kit to detect faces in images and video. - -## Input image guidelines - -For ML Kit to accurately detect faces, input images must contain faces that are represented by sufficient pixel data. In general, each face you want to detect in an image should be at least 100x100 pixels. If you want to detect the contours of faces, ML Kit requires higher resolution input: each face should be at least 200x200 pixels. - -If you are detecting faces in a real-time application, you might also want to consider the overall dimensions of the input images. Smaller images can be processed faster, so to reduce latency, capture images at lower resolutions (keeping in mind the above accuracy requirements) and ensure that the subject's face occupies as much of the image as possible. - -Poor image focus can hurt accuracy. If you aren't getting acceptable results, try asking the user to recapture the image. - -The orientation of a face relative to the camera can also affect what facial features ML Kit detects. See [Face Detection Concepts][7]. - -## 1. Configure the face detector - -Before you apply face detection to an image, if you want to change any of the face detector's default settings, specify those settings with a `VisionFaceDetectorOptions` object. You can change the following settings: - -| Settings | Value | -|----------|-------| -| **PerformanceMode** | **Fast** (default) / **Accurate**

Favor speed or accuracy when detecting faces. | -| **LandmarkMode** | **None** (default) / **All**

Whether to attempt to detect the facial "landmarks"—eyes, ears, nose, cheeks, mouth—of all detected faces. | -| **ContourMode** | **None** (default) / **All**

Whether to detect the contours of facial features. Contours are detected for only the most prominent face in an image. | -| **ClassificationMode** | **None** (default) / **All**

Whether or not to classify faces into categories such as "smiling", and "eyes open". | -| **MinFaceSize** | **CGFloat** (default: 0.1)

The minimum size, relative to the image, of faces to detect. | -| **IsTrackingEnabled** | **False** (default) / **True**

Whether or not to assign faces an ID, which can be used to track faces across images.

Note that when contour detection is enabled, only one face is detected, so face tracking doesn't produce useful results. For this reason, and to improve detection speed, don't enable both contour detection and face tracking. - -For example, build a `VisionFaceDetectorOptions` object like one of the following examples: - -```csharp -// High-accuracy landmark detection and face classification -var options = new VisionFaceDetectorOptions { - PerformanceMode = VisionFaceDetectorPerformanceMode.Accurate, - LandmarkMode = VisionFaceDetectorLandmarkMode.All, - ClassificationMode = VisionFaceDetectorClassificationMode.All -}; - -// Real-time contour detection of multiple faces -var options = new VisionFaceDetectorOptions { - ContourMode = VisionFaceDetectorContourMode.All -}; -``` - -## 2. Run the face detector - -To detect faces in an image, pass the image as a `UIImage` or a `CMSampleBuffer` to the `VisionFaceDetector`'s `ProcessImage` method: - -1. Get an instance of VisionFaceDetector: - - ```csharp - var vision = VisionApi.Create (); - var faceDetector = vision.GetFaceDetector (); - ``` - -2. Create a `VisionImage` object using a `UIImage` or a `CMSampleBuffer`. - - To use a `UIImage`: - - 1. If necessary, rotate the image so that its `ImageOrientation` property is `Up`. - 2. Create a `VisionImage` object using the correctly-rotated `UIImage`. Do not specify any rotation metadata—the default value, `TopLeft`, must be used. - - ```csharp - var image = new VisionImage (anImage); - ``` - - To use a `CMSampleBuffer`: - - 1. Create a `VisionImageMetadata` object that specifies the orientation of the image data contained in the `CMSampleBuffer` buffer. - - For example, if you are using image data captured from the device's back-facing camera: - - ```csharp - var metadata = new VisionImageMetadata (); - - // Using back-facing camera - var devicePosition = AVCaptureDevicePosition.Back; - - var deviceOrientation = UIDevice.CurrentDevice.Orientation; - - switch (deviceOrientation) { - case UIDeviceOrientation.Portrait: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.LeftTop : VisionDetectorImageOrientation.RightTop; - break; - case UIDeviceOrientation.LandscapeLeft: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.BottomLeft : VisionDetectorImageOrientation.TopLeft; - break; - case UIDeviceOrientation.PortraitUpsideDown: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.RightBottom : VisionDetectorImageOrientation.LeftBottom; - break; - case UIDeviceOrientation.LandscapeRight: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.TopRight : VisionDetectorImageOrientation.BottomRight; - break; - case UIDeviceOrientation.FaceUp: - case UIDeviceOrientation.FaceDown: - case UIDeviceOrientation.Unknown: - metadata.Orientation = VisionDetectorImageOrientation.LeftTop; - break; - } - ``` - - 2. Create a `VisionImage` object using the `CMSampleBuffer` object and the rotation metadata: - - ```csharp - var image = new VisionImage (buffer); - image.Metadata = metadata; - ``` - -3. Then, pass the image to the `ProcessImage` method: - - ```csharp - faceDetector.ProcessImage (image, HandleVisionFaceDetectionCallback); - - void HandleVisionFaceDetectionCallback (VisionFace [] faces, NSError error) - { - if (error != null) { - Console.WriteLine (error.Description); - return; - } - - if (faces == null || faces.Length == 0) { - Console.WriteLine ("No faces were found."); - return; - } - - Console.WriteLine ("Faces were found."); - } - - // or using async / await - - try { - var faces = await faceDetector.ProcessImageAsync (image); - Console.WriteLine (faces != null || faces.Length == 0 ? "No faces were found." : "Faces were found"); - } catch (NSErrorException ex) { - Console.WriteLine (ex.Error.Description); - } - ``` - -## 3. Get information about detected faces - -If the face detection operation succeeds, the face detector passes an array of `VisionFace` objects to the completion handler. Each `VisionFace` object represents a face that was detected in the image. For each face, you can get its bounding coordinates in the input image, as well as any other information you configured the face detector to find. For example: - -```csharp -foreach (var face in faces) { - // Boundaries of face in image - var frame = face.Frame; - if (face.HasHeadEulerAngleY) { - var rotY = face.HeadEulerAngleY; // Head is rotated to the right rotY degrees - } - if (face.HasHeadEulerAngleZ) { - var rotY = face.HeadEulerAngleZ; // Head is rotated upward rotZ degrees - } - // If landmark detection was enabled (mouth, ears, eyes, cheeks, and - // nose available): - if (face.GetLandmark (FaceLandmarkType.LeftEye) is VisionFaceLandmark leftEye) { - var leftEyePosition = leftEye.Position; - } - // If contour detection was enabled: - if (face.GetContour (FaceContourType.LeftEye) is VisionFaceContour leftEyeContour) { - var leftEyePoints = leftEyeContour.Points; - } - if (face.GetContour (FaceContourType.UpperLipBottom) is VisionFaceContour upperLipBottomContour) { - var upperLipBottomPoints = upperLipBottomContour.Points; - } - // If classification was enabled: - if (face.HasSmilingProbability) { - var smilingProbability = face.SmilingProbability; - } - if (face.HasRightEyeOpenProbability) { - var rightEyeOpenProbability = face.RightEyeOpenProbability; - } - // If face tracking was enabled: - if (face.HasTrackingId) { - var trackingId = face.TrackingId; - } -} -``` - ---- - -# Barcode Scanning - -With ML Kit's barcode scanning API, you can read data encoded using most standard barcode formats. - -Barcodes are a convenient way to pass information from the real world to your app. In particular, when using 2D formats such as QR code, you can encode structured data such as contact information or WiFi network credentials. Because ML Kit can automatically recognize and parse this data, your app can respond intelligently when a user scans a barcode. - -## Key capabilities - -| | | -|-------|-------| -| **Reads most standard formats** | Linear formats: Codabar, Code 39, Code 93, Code 128, EAN-8, EAN-13, ITF, UPC-A, UPC-E

2D formats: Aztec, Data Matrix, PDF417, QR Code | -| **Automatic format detection** | Scan for all supported barcode formats at once, without having to specify the format you're looking for. Or, boost scanning speed by restricting the detector to only the formats you're interested in. | -| **Extracts structured data** | Structured data stored using one of the supported 2D formats are automatically parsed. Supported information types include URLs, contact information, calendar events, email addresses, phone numbers, SMS message prompts, ISBNs, WiFi connection information, geographic location, and AAMVA-standard driver information. | -| **Works with any orientation** | Barcodes are recognized and scanned regardless of their orientation: right-side-up, upside-down, or sideways. | - -# Scan Barcodes with ML Kit on iOS - -You can use ML Kit to recognize and decode barcodes. - -## Input image guidelines - -* For ML Kit to accurately read barcodes, input images must contain barcodes that are represented by sufficient pixel data. In general, the smallest meaningful unit of the barcode should be at least 2 pixels wide (and for 2-dimensional codes, 2 pixels tall). - - For example, EAN-13 barcodes are made up of bars and spaces that are 1, 2, 3, or 4 units wide, so an EAN-13 barcode image ideally has bars and spaces that are at least 2, 4, 6, and 8 pixels wide. Because an EAN-13 barcode is 95 units wide in total, the barcode should be at least 190 pixels wide. - - Denser formats, such as PDF417, need greater pixel dimensions for ML Kit to reliably read them. For example, a PDF417 code can have up to 34 17-unit wide "words" in a single row, which would ideally be at least 1156 pixels wide. - -* Poor image focus can hurt scanning accuracy. If you aren't getting acceptable results, try asking the user to recapture the image. - -* If you are scanning barcodes in a real-time application, you might also want to consider the overall dimensions of the input images. Smaller images can be processed faster, so to reduce latency, capture images at lower resolutions (keeping in mind the above accuracy requirements) and ensure that the barcode occupies as much of the image as possible. - -## 1. Configure the barcode detector - -If you know which barcode formats you expect to read, you can improve the speed of the barcode detector by configuring it to only detect those formats. - -For example, to detect only Aztec code and QR codes, build a `VisionBarcodeDetectorOptions` object as in the following example: - -```csharp -var options = new VisionBarcodeDetectorOptions (VisionBarcodeFormat.All); -``` - -The following formats are supported: - -* Code128 -* Code39 -* Code93 -* CodaBar -* EAN13 -* EAN8 -* ITF -* UPCA -* UPCE -* QRCode -* PDF417 -* Aztec -* DataMatrix - -> ![note_icon] **_Note:_** _For a Data Matrix code to be recognized, the code must intersect the center point of the input image. Consequently, only one Data Matrix code can be recognized in an image._ - -## 2. Run the barcode detector - -To scan barcodes in an image, pass the image as a `UIImage` or a `CMSampleBuffer` to the `VisionBarcodeDetector`'s `Detect` method: - -1. Get an instance of VisionFaceDetector: - - ```csharp - var vision = VisionApi.Create (); - var faceDetector = vision.GetBarcodeDetector (options); - ``` - -2. Create a `VisionImage` object using a `UIImage` or a `CMSampleBuffer`. - - To use a `UIImage`: - - 1. If necessary, rotate the image so that its `ImageOrientation` property is `Up`. - 2. Create a `VisionImage` object using the correctly-rotated `UIImage`. Do not specify any rotation metadata—the default value, `TopLeft`, must be used. - - ```csharp - var image = new VisionImage (anImage); - ``` - - To use a `CMSampleBuffer`: - - 1. Create a `VisionImageMetadata` object that specifies the orientation of the image data contained in the `CMSampleBuffer` buffer. - - For example, if you are using image data captured from the device's back-facing camera: - - ```csharp - var metadata = new VisionImageMetadata (); - - // Using back-facing camera - var devicePosition = AVCaptureDevicePosition.Back; - - var deviceOrientation = UIDevice.CurrentDevice.Orientation; - - switch (deviceOrientation) { - case UIDeviceOrientation.Portrait: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.LeftTop : VisionDetectorImageOrientation.RightTop; - break; - case UIDeviceOrientation.LandscapeLeft: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.BottomLeft : VisionDetectorImageOrientation.TopLeft; - break; - case UIDeviceOrientation.PortraitUpsideDown: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.RightBottom : VisionDetectorImageOrientation.LeftBottom; - break; - case UIDeviceOrientation.LandscapeRight: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.TopRight : VisionDetectorImageOrientation.BottomRight; - break; - case UIDeviceOrientation.FaceUp: - case UIDeviceOrientation.FaceDown: - case UIDeviceOrientation.Unknown: - metadata.Orientation = VisionDetectorImageOrientation.LeftTop; - break; - } - ``` - - 2. Create a `VisionImage` object using the `CMSampleBuffer` object and the rotation metadata: - - ```csharp - var image = new VisionImage (buffer); - image.Metadata = metadata; - ``` - -3. Then, pass the image to the `Detect` method: - - ```csharp - barcodeDetector.Detect (image, HandleVisionBarcodeDetectionCallback); - - void HandleVisionBarcodeDetectionCallback (VisionBarcode [] barcodes, NSError error) - { - if (error != null) { - Console.WriteLine (error.Description); - return; - } - - if (barcodes == null || barcodes.Length == 0) { - Console.WriteLine ("No barcodes were found."); - return; - } - - Console.WriteLine ("Barcodes were found."); - } - - // or using async / await - - try { - var barcodes = await barcodeDetector.DetectAsync (image); - Console.WriteLine (barcodes != null || barcodes.Length == 0 ? "No barcodes were found." : "Barcodes were found"); - } catch (NSErrorException ex) { - Console.WriteLine (ex.Error.Description); - } - ``` - -## 3. Get information from barcodes - -If the barcode recognition operation succeeds, the detector returns an array of `VisionBarcode` objects. Each `VisionBarcode` object represents a barcode that was detected in the image. For each barcode, you can get its bounding coordinates in the input image, as well as the raw data encoded by the barcode. Also, if the barcode detector was able to determine the type of data encoded by the barcode, you can get an object containing parsed data. - -For example: - -```csharp -foreach (var barcode in barcodes) { - var corners = barcode.CornerPoints; - var displayValue = barcode.DisplayValue; - var rawValue = barcode.RawValue; - var valueType = barcode.ValueType; - - switch (valueType) { - case VisionBarcodeValueType.WiFi: - var ssid = barcode.Wifi.Ssid; - var password = barcode.Wifi.Password; - var encryptionType = barcode.Wifi.Type; - break; - case VisionBarcodeValueType.Url: - var title = barcode.Url.Title; - var url = barcode.Url.Url; - break; - default: - // See API reference for all supported value types - break; - } -} -``` - -## Tips to improve real-time performance - -If you want to scan barcodes in a real-time application, follow these guidelines to achieve the best framerates: - -* Throttle calls to the detector. If a new video frame becomes available while the detector is running, drop the frame. - -* If you are using the output of the detector to overlay graphics on the input image, first get the result from ML Kit, then render the image and overlay in a single step. By doing so, you render to the display surface only once for each input frame. - -* If you use the Camera2 API, capture images in `ImageFormat.YUV_420_888` format. - - If you use the older Camera API, capture images in `ImageFormat.NV21` format. - -* Consider capturing images at a lower resolution. However, also keep in mind this API's image dimension requirements. - ---- - -# Image Labeling - -With ML Kit's image labeling APIs, you can recognize entities in an image without having to provide any additional contextual metadata, using either an on-device API or a cloud-based API. - -Image labeling gives you insight into the content of images. When you use the API, you get a list of the entities that were recognized: people, things, places, activities, and so on. Each label found comes with a score that indicates the confidence the ML model has in its relevance. With this information, you can perform tasks such as automatic metadata generation and content moderation. - -## Choose between on-device and Cloud APIs - -| | On-device | Cloud | -|--|-----------|-------| -| **Pricing** | Free | Free for first 1000 uses of this feature per month: see [Pricing][1] | -| **Label coverage** | 400+ labels that cover the most commonly-found concepts in photos. See below. | 10,000+ labels in many categories. See below.

Also, try the [Cloud Vision API demo][2] to see what labels can be found for an image you provide. | -| **Knowledge Graph entity ID support** | ![available_icon] | ![available_icon] | - -### Example on-device labels - -The device-based API supports 400+ labels, such as the following examples: - -| Category | Example labels | -|------------|--------------------------------------| -| People | Crowd
Selfie
Smile | -| Activities | Dancing
Eating
Surfing | -| Things | Car
Piano
Receipt | -| Animals | Bird
Cat
Dog | -| Plants | Flower
Fruit
Vegetable | -| Places | Beach
Lake
Mountain | - -### Example cloud labels - -The cloud-based API supports 10,000+ labels, such as the following examples: - -| Category | Example labels | Category | Example labels -| ---------|----------------|----------|--------------- -| Arts & entertainment | Sculpture
Musical Instrument
Dance | Astronomical objects | Comet
Galaxy
Star | -| Business & industrial | Restaurant
Factory
Airline | Colors | Red
Green
Blue | -| Design | Floral
Pattern
Wood Stain | Drink | Coffee
Tea
Milk | -| Events | Meeting
Picnic
Vacation | Fictional characters | Santa Claus
Superhero
Mythical creature | -| Food | Casserole
Fruit
Potato chip | Home & garden | Laundry basket
Dishwasher
Fountain | -| Activities | Wedding
Dancing
Motorsport | Materials | Ceramic
Textile
Fiber | -| Media | Newsprint
Document
Sign | Modes of transport | Aircraft
Motorcycle
Subway | -| Occupations | Actor
Florist
Police | Organisms | Plant
Animal
Fungus | -| Organizations | Government
Club
College | Places | Airport
Mountain
Tent | -| Technology | Robot
Computer
Solar panel | Things | Bicycle
Pipe
Doll | - -## Google Knowledge Graph entity IDs - -In addition the text description of each label that ML Kit returns, it also returns the label's Google Knowledge Graph entity ID. This ID is a string that uniquely identifies the entity represented by the label, and is the same ID used by the [Knowledge Graph Search API][8]. You can use this string to identify an entity across languages, and independently of the formatting of the text description. - -# Label Images with ML Kit on iOS - -You can use ML Kit to label objects recognized in an image, using either an on-device model or a cloud model. - -## On-device image labeling - -To use the on-device image labeling model, configure and run the the image labeler as described below. - -### 1. Configure the image labeler - -By default, the on-device image labeler returns only labels that have a confidence score of 0.5 or greater. If you want to change this setting, create a `VisionLabelDetectorOptions` object as in the following example: - -```csharp -var options = new VisionLabelDetectorOptions (.6f); -``` - -### 2. Run the image labeler - -To recognize and label entities in an image, pass the image as a `UIImage` or a `CMSampleBuffer` to the `VisionLabelDetector`'s `Detect` method: - -1. Get an instance of `VisionLabelDetector`: - - ```csharp - var vision = VisionApi.Create (); - var labelDetector = vision.GetLabelDetector (options); - ``` - -2. Create a `VisionImage` object using a `UIImage` or a `CMSampleBuffer`. - - To use a `UIImage`: - - 1. If necessary, rotate the image so that its `ImageOrientation` property is `Up`. - 2. Create a `VisionImage` object using the correctly-rotated `UIImage`. Do not specify any rotation metadata—the default value, `TopLeft`, must be used. - - ```csharp - var image = new VisionImage (anImage); - ``` - - To use a `CMSampleBuffer`: - - 1. Create a `VisionImageMetadata` object that specifies the orientation of the image data contained in the `CMSampleBuffer` buffer. - - For example, if you are using image data captured from the device's back-facing camera: - - ```csharp - var metadata = new VisionImageMetadata (); - - // Using back-facing camera - var devicePosition = AVCaptureDevicePosition.Back; - - var deviceOrientation = UIDevice.CurrentDevice.Orientation; - - switch (deviceOrientation) { - case UIDeviceOrientation.Portrait: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.LeftTop : VisionDetectorImageOrientation.RightTop; - break; - case UIDeviceOrientation.LandscapeLeft: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.BottomLeft : VisionDetectorImageOrientation.TopLeft; - break; - case UIDeviceOrientation.PortraitUpsideDown: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.RightBottom : VisionDetectorImageOrientation.LeftBottom; - break; - case UIDeviceOrientation.LandscapeRight: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.TopRight : VisionDetectorImageOrientation.BottomRight; - break; - case UIDeviceOrientation.FaceUp: - case UIDeviceOrientation.FaceDown: - case UIDeviceOrientation.Unknown: - metadata.Orientation = VisionDetectorImageOrientation.LeftTop; - break; - } - ``` - - 2. Create a `VisionImage` object using the `CMSampleBuffer` object and the rotation metadata: - - ```csharp - var image = new VisionImage (buffer); - image.Metadata = metadata; - ``` - -3. Then, pass the image to the `Detect` method: - - ```csharp - labelDetector.Detect (image, HandleVisionLabelDetectionCallback); - - void HandleVisionLabelDetectionCallback (VisionLabel [] labels, NSError error) - { - if (error != null) { - Console.WriteLine (error.Description); - return; - } - - if (labels == null || labels.Length == 0) { - Console.WriteLine ("No labels were found."); - return; - } - - Console.WriteLine ("Labels were found."); - } - - // or using async / await - - try { - var labels = await labelDetector.DetectAsync (image); - Console.WriteLine (labels != null || labels.Length == 0 ? "No labels were found." : "Labels were found"); - } catch (NSErrorException ex) { - Console.WriteLine (ex.Error.Description); - } - ``` - -### 3. Get information about labeled objects - -If image labeling succeeds, an array of `VisionLabel` objects will be passed to the completion handler. From each object, you can get information about a feature recognized in the image. - -For example: - -```csharp -foreach (var label in labels) { - var labelText = label.Label; - var entityId = label.EntityId; - var confidence = label.Confidence; -} -``` - -### Tips to improve real-time performance - -If you want to label images in a real-time application, follow these guidelines to achieve the best framerates: - -* Throttle calls to the image labeler. If a new video frame becomes available while the image labeler is running, drop the frame. - -## Cloud image labeling - -To use the Cloud-based image labeling model, configure and run the the image labeler as described below. - -> ![note_icon] _Use of ML Kit to access Cloud ML functionality is subject to the [Google Cloud Platform License Agreement][5] and [Service Specific Terms][6], and billed accordingly. For billing information, see the Firebase [Pricing][1] page._ - -### 1. Configure the image labeler - -By default, the Cloud detector uses the stable version of the model and returns up to 10 results. If you want to change either of these settings, specify them with a `VisionCloudDetectorOptions` object as in the following example: - -```csharp -var options = new VisionCloudDetectorOptions { - ModelType = VisionCloudModelType.Latest, - MaxResults = 5 -}; -``` - -In the next step, pass the VisionCloudDetectorOptions object when you create the Cloud detector object. - -### 2. Run the image labeler - -To recognize and label entities in an image, pass the image as a UIImage or a CMSampleBufferRef to the `VisionCloudLabelDetector`'s `Detect` method: - -1. Get an instance of `VisionCloudLabelDetector`: - -```csharp -var vision = VisionApi.Create (); -var labelDetector = vision.GetCloudLabelDetector (options); -``` - -2. Create a `VisionImage` object using a `UIImage` or a `CMSampleBuffer`. - - To use a `UIImage`: - - 1. If necessary, rotate the image so that its `ImageOrientation` property is `Up`. - 2. Create a `VisionImage` object using the correctly-rotated `UIImage`. Do not specify any rotation metadata—the default value, `TopLeft`, must be used. - - ```csharp - var image = new VisionImage (anImage); - ``` - - To use a `CMSampleBuffer`: - - 1. Create a `VisionImageMetadata` object that specifies the orientation of the image data contained in the `CMSampleBuffer` buffer. - - For example, if you are using image data captured from the device's back-facing camera: - - ```csharp - var metadata = new VisionImageMetadata (); - - // Using back-facing camera - var devicePosition = AVCaptureDevicePosition.Back; - - var deviceOrientation = UIDevice.CurrentDevice.Orientation; - - switch (deviceOrientation) { - case UIDeviceOrientation.Portrait: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.LeftTop : VisionDetectorImageOrientation.RightTop; - break; - case UIDeviceOrientation.LandscapeLeft: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.BottomLeft : VisionDetectorImageOrientation.TopLeft; - break; - case UIDeviceOrientation.PortraitUpsideDown: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.RightBottom : VisionDetectorImageOrientation.LeftBottom; - break; - case UIDeviceOrientation.LandscapeRight: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.TopRight : VisionDetectorImageOrientation.BottomRight; - break; - case UIDeviceOrientation.FaceUp: - case UIDeviceOrientation.FaceDown: - case UIDeviceOrientation.Unknown: - metadata.Orientation = VisionDetectorImageOrientation.LeftTop; - break; - } - ``` - - 2. Create a `VisionImage` object using the `CMSampleBuffer` object and the rotation metadata: - - ```csharp - var image = new VisionImage (buffer); - image.Metadata = metadata; - ``` - -3. Then, pass the image to the `Detect` method: - - ```csharp - labelDetector.Detect (image, HandleVisionCloudLabelDetectionCompletion); - - void HandleVisionCloudLabelDetectionCompletion (VisionCloudLabel [] labels, NSError error) - { - if (error != null) { - Console.WriteLine (error.Description); - return; - } - - if (labels == null || labels.Length == 0) { - Console.WriteLine ("No labels were found."); - return; - } - - Console.WriteLine ("Labels were found."); - } - - // or using async / await - - try { - var labels = await labelDetector.DetectAsync (image); - Console.WriteLine (labels != null || labels.Length == 0 ? "No labels were found." : "Labels were found"); - } catch (NSErrorException ex) { - Console.WriteLine (ex.Error.Description); - } - ``` - -### 3. Get information about labeled objects - -If image labeling succeeds, an array of `VisionCloudLabel` objects will be passed to the completion handler. From each object, you can get information about an entity recognized in the image. This information doesn't contain frame or other location data. - -For example: - -```csharp -foreach (var label in labels) { - var labelText = label.Label; - var entityId = label.EntityId; - var confidence = label.Confidence; -} -``` - ---- - -# Landmark Recognition - -With ML Kit's landmark recognition API, you can recognize well-known landmarks in an image. - -When you pass an image to this API, you get the landmarks that were recognized in it, along with each landmark's geographic coordinates and the region of the image the landmark was found. You can use this information to automatically generate image metadata, create individualized experiences for users based on the content they share, and more. - -## Key capabilities - -| | | -|-------|-------| -| **Recognizes well-known landmarks** | Get the name and geographic coordinates of natural and constructed landmarks, as well as the region of the image the landmark was found. | -| **Get Google Knowledge Graph entity IDs** | A Knowledge Graph entity ID is a string that uniquely identifies the landmark that was recognized, and is the same ID used by the [Knowledge Graph Search API][8]. You can use this string to identify an entity across languages, and independently of the formatting of the text description. | -| **Low-volume use free** | Free for first 1000 uses of this feature per month: see [Pricing][1]. | - -# Recognize Landmarks with ML Kit on iOS - -You can use ML Kit to recognize well-known landmarks in an image. - -> ![note_icon] _Use of ML Kit to access Cloud ML functionality is subject to the [Google Cloud Platform License Agreement][5] and [Service Specific Terms][6], and billed accordingly. For billing information, see the Firebase [Pricing][1] page._ - -## Configure the landmark detector - -By default, the Cloud detector uses the stable version of the model and returns up to 10 results. If you want to change either of these settings, specify them with a `VisionCloudDetectorOptions` object as in the following example: - -```csharp -var options = new VisionCloudDetectorOptions { - ModelType = VisionCloudModelType.Latest, - MaxResults = 20 -}; -``` - -In the next step, pass the VisionCloudDetectorOptions object when you create the Cloud detector object. - -## Run the landmark detector - -To recognize and label entities in an image, pass the image as a `UIImage` or a `CMSampleBuffer` to the `VisionCloudLandmarkDetector's`'s `Detect` method: - -1. Get an instance of `VisionCloudLandmarkDetector's`: - - ```csharp - var vision = VisionApi.Create (); - var landmarkDetector = vision.GetCloudLandmarkDetector (options); - ``` - -2. Create a `VisionImage` object using a `UIImage` or a `CMSampleBuffer`. - - To use a `UIImage`: - - 1. If necessary, rotate the image so that its `ImageOrientation` property is `Up`. - 2. Create a `VisionImage` object using the correctly-rotated `UIImage`. Do not specify any rotation metadata—the default value, `TopLeft`, must be used. - - ```csharp - var image = new VisionImage (anImage); - ``` - - To use a `CMSampleBuffer`: - - 1. Create a `VisionImageMetadata` object that specifies the orientation of the image data contained in the `CMSampleBuffer` buffer. - - For example, if you are using image data captured from the device's back-facing camera: - - ```csharp - var metadata = new VisionImageMetadata (); - - // Using back-facing camera - var devicePosition = AVCaptureDevicePosition.Back; - - var deviceOrientation = UIDevice.CurrentDevice.Orientation; - - switch (deviceOrientation) { - case UIDeviceOrientation.Portrait: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.LeftTop : VisionDetectorImageOrientation.RightTop; - break; - case UIDeviceOrientation.LandscapeLeft: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.BottomLeft : VisionDetectorImageOrientation.TopLeft; - break; - case UIDeviceOrientation.PortraitUpsideDown: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.RightBottom : VisionDetectorImageOrientation.LeftBottom; - break; - case UIDeviceOrientation.LandscapeRight: - metadata.Orientation = devicePosition == AVCaptureDevicePosition.Front ? VisionDetectorImageOrientation.TopRight : VisionDetectorImageOrientation.BottomRight; - break; - case UIDeviceOrientation.FaceUp: - case UIDeviceOrientation.FaceDown: - case UIDeviceOrientation.Unknown: - metadata.Orientation = VisionDetectorImageOrientation.LeftTop; - break; - } - ``` - - 2. Create a `VisionImage` object using the `CMSampleBuffer` object and the rotation metadata: - - ```csharp - var image = new VisionImage (buffer); - image.Metadata = metadata; - ``` - -3. Then, pass the image to the `Detect` method: - - ```csharp - landmarkDetector.Detect (image, HandleVisionCloudLandmarkDetectionCallback); - - void HandleVisionCloudLandmarkDetectionCallback (VisionCloudLandmark [] landmarks, NSError error) - { - if (error != null) { - Console.WriteLine (error.Description); - return; - } - - if (landmarks == null || landmarks.Length == 0) { - Console.WriteLine ("No landmarks were found."); - return; - } - - Console.WriteLine ("Landmarks were found."); - } - - // or using async / await - - try { - var landmarks = await landmarkDetector.DetectAsync (image); - Console.WriteLine (landmarks != null || landmarks.Length == 0 ? "No landmarks were found." : "Landmarks were found"); - } catch (NSErrorException ex) { - Console.WriteLine (ex.Error.Description); - } - ``` - -## Get information about the recognized landmarks - -If landmark recognition succeeds, an array of `VisionCloudLandmark` objects will be passed to the completion handler. From each object, you can get information about a landmark recognized in the image. - -For example: - -```csharp -foreach (var landmark in landmarks) { - var landmarkDesc = landmark.Landmark; - var boundingPoly = landmark.Frame; - var entityId = landmark.EntityId; - - foreach (var location in landmark.Locations) { - // A landmark can have multiple locations: for example, the location the image - // was taken, and the location of the landmark depicted. - var latitude = location.Latitude; - var longitude = location.Longitude; - } - - var confidence = landmark.Confidence; -} -``` - ---- - -# Protect your ML Kit iOS app's Cloud credentials - -If your iOS app uses one of ML Kit's cloud APIs, before you launch your app in production, you should take some additional steps to prevent unauthorized API access. - -Read this [document][9] to learn more about this. - -[1]: https://firebase.google.com/pricing -[2]: https://cloud.google.com/vision/docs/drag-and-drop -[3]: https://firebase.google.com/docs/ml-kit/recognize-text -[4]: https://firebase.google.com/docs/ml-kit/ios/secure-api-key -[5]: https://cloud.google.com/terms/ -[6]: https://cloud.google.com/terms/service-terms -[7]: https://firebase.google.com/docs/ml-kit/face-detection-concepts -[8]: https://developers.google.com/knowledge-graph/ -[9]: https://firebase.google.com/docs/ml-kit/ios/secure-api-key -[10]: https://firebase.google.com/console/ -[11]: http://support.google.com/firebase/answer/7015592 -[note_icon]: https://cdn3.iconfinder.com/data/icons/UltimateGnome/22x22/apps/gnome-app-install-star.png -[warning_icon]: https://cdn2.iconfinder.com/data/icons/freecns-cumulus/32/519791-101_Warning-20.png -[available_icon]: https://cdn3.iconfinder.com/data/icons/flat-actions-icons-9/512/Tick_Mark-24.png diff --git a/docs/Google/AppIndexing/Details.md b/docs/Google/AppIndexing/Details.md deleted file mode 100755 index a6eb91570..000000000 --- a/docs/Google/AppIndexing/Details.md +++ /dev/null @@ -1,23 +0,0 @@ -App Indexing puts your app in front of users who use Google Search. It works by indexing the URL patterns you provide in your app manifest and using API calls from your app to make content within your app available to both existing and new users. Specifically, when you support URLs for your app content, iOS users can go directly to it from Search results on their device. Finally, Google uses App Indexing API calls from your app as a ranking signal for your URLs. - -## How App Indexing works for iOS - -### Support HTTP URLs to your mobile app. - -iOS apps support HTTP URLs and use site association to verify the relationship between the app and its website. This allows Google systems to index URLs that work for both your site and your app and to serve them in search results. - -Once you associate your app to your website, Google systems quickly recognize the association and begin the crawling and discovery process for your app URLs. This can take between 24 hours and a number of days, depending on a number of factors. Because most app content is currently associated with web content, crawl scheduling works in a fashion similar to that of webpages: Google take into account multiple factors like frequency of content updates, server load, importance, and freshness of the page. Google will send you a message in Search console when content from your app shows up in search (“first impression”). If it’s been a couple weeks and you still don’t see any app links in search, check for crawl errors. Read about [Google Search crawl frequency][1] on Google Help Center. - -[1]: https://support.google.com/webmasters/answer/34439 - -### Add the App Indexing API or SDK. - -Use the App Indexing SDK for iOS 9. The use of Google SDK enhances ranking performance for the URLs and provides the basis for link titles and content snippets. This provides the titles and description snippets associated with your content, as well as the history of actions to your app. Users of your app can delete past activity in apps at https://history.google.com/. - -### Check your implementation. - -Test URLs to your app in your development environment to make sure they lead to the correct content. - -## Technical requirements - -Google App Indexing documentation for iOS 9 serves iOS universal links from Google Search in Safari. App Indexing for iOS versions 7 and 8 is now deprecated and no longer available for new integrations. \ No newline at end of file diff --git a/docs/Google/AppIndexing/GettingStarted.md b/docs/Google/AppIndexing/GettingStarted.md deleted file mode 100755 index dafa26936..000000000 --- a/docs/Google/AppIndexing/GettingStarted.md +++ /dev/null @@ -1,114 +0,0 @@ -## Support HTTP URLs - -App Indexing for iOS 9 uses HTTP URLs to direct users to content in your app. If you’ve already followed the instructions to [support universal links][1] in your app, you can skip this section. Otherwise, do the following: - -### Create the app-to-site association. - -This involves two things: - -- Add a `com.apple.developer.associated-domains` entitlement in entitlement.plist file that lists each domain associated with your app. -- Create an `apple-app-site-association` file for each associated domain with the content your app supports and host it at the root level. - -*Note: The association file must be hosted on a domain that supports HTTPS/TLS, even if the HTTP deep links are not themselves served via HTTPS.* - -#### Preparing Your Website - -1. Create a apple-app-site-association file. Note that there’s no .json file type -2. Place the apple-app-site-association file and identify app IDs and paths on your website. You can define several apps in this file and iOS will follow the app order when looking for a match so you can specify different apps to handle different paths on your website. - -Here's an example of file's content: - -``` -{ - "applinks": { - "apps": [], - "details": [ - { - "appID": "9JA89QQLNQ.com.apple.wwdc", - "paths": [ "/wwdc/news/", "/videos/wwdc/2015/*"] - }, - { - "appID": "TeamID.BundleID2", - "paths": [ "*" ] - } - ] - } -} -``` - -The apps key in an apple-app-site-association file must be present and its value must be an empty array. The value of the details key is an array of dictionaries, one dictionary per app that your website supports. The order of the dictionaries in the array determines the order the system follows when looking for a match, so you can specify an app to handle a particular part of your website. - -Each app-specific dictionary contains an appID key and a paths key. The value of the appID key is the app’s team ID and the bundle ID; the value of the paths key is an array of strings that specify the parts of your website that are supported by the app and the parts of your website that you don’t want to associate with the app. To specify an area that should not be handled as a universal link, add “NOT ” (including a space after the T) to the beginning of the path string. For example: - -``` -"paths": [ "/wwdc/news/", "NOT /videos/wwdc/2010/*", "/videos/wwdc/201?/*"] -``` - -Upload the apple-app-site-association file in the root of your HTTPS web server. The file should be accessible without redirects at http:///apple-app-site-association - -### Preparing your App - -#### Creating an App ID and provisioning profile - -To make Universal Links works, you need to create a Provisioning Profile with an Explicit App Id with Associated Domains Services enabled. To achieve this, follow this steps: - -1. On the Apple Developer Member Center home page, click Certificates, Identifiers & Profiles. -2. On the Certificates, Identifiers & Profiles page, under the iOS Apps column, click Identifiers. -3. On the iOS App IDs page, click on the **+** button. -4. On the Registering an App ID page, enter an App ID Description/Name, select **Explicit App ID**, enter your app’s Bundle ID, enable **Associated Domains -** Service and then click Continue. -5. On the Confirm your App ID page, click Submit. -6. On the Registration complete page, click Done. -7. Create a provisioning profile with the new App ID. - -#### Enabling Associated Domains in your app - -1. In you Xamarin iOS project, open the Entitlements.plist file -2. Open the Associated Domains header and check **Enable Associated Domains** -3. Add your domains starting with `applinks:`, for example: `applinks:xamarin.com` - -#### Add handling for universal links to your app. - -Adopt the [UIApplicationDelegate][2] methods so that your app opens the appropriate app content in response to the user’s click from search results. - -```csharp -public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler) -{ - if (userActivity.ActivityType == NSUserActivityType.BrowsingWeb) { - // Do your magic here. - } - - return true; -} -``` - -[1]: https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html#//apple_ref/doc/uid/TP40016308-CH12-SW1 -[2]: https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intf/UIApplicationDelegate - -## Register your app to Google system - -Call the `RegisterApp` method in your `FinishedLaunching` method. - -```csharp -AppIndexing.SharedInstance.RegisterApp ("YOUR_ITUNES_ID"); -``` - -You're all set! Once Google's crawlers discover the the URLs in your association file, Google will automatically start indexing any existing or new HTTP deep links to your app. - -## Check Your Implementation - -Once you've completed setup for App Indexing, you can verify your universal links prior to their appearance in Google Search by tapping a universal link in Safari on your device and making sure that it takes you to the right place in the app. - -*Note: You cannot test universal links on simulator.* - -## Enhance Your Search Performance - -A key way to enhance your app's ranking is to provide high-quality content in your site and your app. Specifically, keep in mind the following: - -- Make sure your associated site meets Google's [design and content guidelines][3]. -- Follow the same layout practices recommended for your [mobile-friendly homepage][4]. For example, keep your titles short and avoid full-width menus. - -In order to ensure a great search experience for users, Google may take corrective action in cases where they see abuse, deception, or other actions that hurt the search experience for users. This can include actions such as demoting or removing your app deep links from Google Search results. - -[3]: https://support.google.com/webmasters/answer/35769?vid=1-635785548570479109-2344616627#design_and_content_guidelines -[4]: https://developers.google.com/web/fundamentals/layouts/principles/ \ No newline at end of file diff --git a/docs/Google/AppInvite/Details.md b/docs/Google/AppInvite/Details.md deleted file mode 100755 index 0445d101d..000000000 --- a/docs/Google/AppInvite/Details.md +++ /dev/null @@ -1,27 +0,0 @@ - -App Invites provide a powerful way to organically grow your app, user-to-user. Your users recommend your app to their friends using personalized, contextual invitations powered by Google. App Invites provide a great onboarding experience to your new users. Google optimizes your app install rates by reducing friction and using relevant context at every step of the user invitation flow. - -### App Invites flow - -App Invites always begins with a user sending an invite from your app. The following diagram illustrates the App Invites flow. - -![AppInviteFlow](https://developers.google.com/app-invites/images/ai-ios-flow.svg) - -### Sending an invitation - - -You allow a user to send an invitation from your application by using the `IInviteBuilder` interface in your app’s ViewController file. The invite must include a title and can also include a message and deep link data. - -The Open method of `IInviteBuilder` opens the contact chooser dialog where the user selects the contacts to invite. The invite can be sent via email or SMS. - -### Receiving an invitation - -When a user receives and choose to open an invitation URL, the invitation flow branches according to whether or not your app is already installed on the recipient’s device. If the recipient doesn’t have your app, the flow branches to let the user install it. If the recipient is already one of your users, then the optional deep link information in the invite passes to your app for processing. - -**App is already installed** - -If the recipient has already installed your app, the app will receive the invite URL containing the optional deep link data. - -**App is not installed** - -If the recipient has not yet installed the app, they can choose to install the app from the iTunes App Store. When the app is opened for the first time, the App Invites SDK will supply a deep link if one is available. diff --git a/docs/Google/AppInvite/GettingStarted.md b/docs/Google/AppInvite/GettingStarted.md deleted file mode 100755 index 1967e56cf..000000000 --- a/docs/Google/AppInvite/GettingStarted.md +++ /dev/null @@ -1,113 +0,0 @@ -Configuring your App --------------------- - -Google provides an easy to use configuration web tool to generate a config file for your app: - -1. Open [Google's configuration tool][1] to create a config file for your app. -2. Enter your app's name and iOS Bundle ID and click continue -3. Enter your App Store ID and click *Enable App Invites* - (If you don't have an App Store ID you can use one of our favorites - 1000846120 or 783488172) -4. Click *continue* to generate the configuration files -5. Click *Download Google-Service-Info.plist* -6. Add `GoogleService-Info.plist` to your Xamarin.iOS app project and set the *Build Action* to `BundleResource` -7. In your Xamarin.iOS app project's `Info.plist` file, add the following URL Types: - - Identifier: `google` Role: `Editor` URL Schemes: `your.app.bundle.id` - - Identifier: `google` Role: `Editor` URL Schemes: `value of REVERSED_CLIENT_ID from GoogleService-Info.plist` - - -Setup your AppDelegate ----------------------- - -In order for App Invites to work properly, you must tell the SDK about some of your application lifecycle events. - -In your `AppDelegate.cs`, in the `FinishedLaunching (..)` override, you should add the following code to the start of the method: - -```csharp -NSError configureError; -Context.SharedInstance.Configure (out configureError); -if (configureError != null) - Console.WriteLine ("Error configuring the Google context: {0}", configureError); - -Invite.ApplicationDidFinishLaunching (); -``` - -Next, add the following override to your AppDelegate class (or if it already exists, add the code inside the method to the existing implementation: - -```csharp -public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation) -{ - // Handle App Invite requests - var invite = Invite.HandleUrl (url, sourceApplication, annotation); - if (invite != null) { - var message =string.Format ("Deep link from {0} \nInvite ID: {1}\nApp URL: {2}", - sourceApplication, invite.InviteId, invite.DeepLink); - new UIAlertView (@"Deep-link Data", message, null, "OK").Show (); - return true; - } - - return SignIn.SharedInstance.HandleUrl (url, sourceApplication, annotation); -} -``` - - -Signing In ----------- - -In order for app invites to work, your app's user must sign in to their Google account. To do this, you should request a login in your View Controller. This can be done in the `ViewDidLoad` override: - -```csharp -// Sign the user in automatically -SignIn.SharedInstance.UIDelegate = this; -SignIn.SharedInstance.Delegate = this; -SignIn.SharedInstance.SignInUser (); -``` -You also must implement `ISignInDelegate` as well as `ISignInUIDelegate` and provide a `DidSignIn` method to know when the sign-in completed and if it was successful: - -```csharp -public void DidSignIn (SignIn signIn, GoogleUser user, NSError error) -{ - if (user != null && error == null) - // Enable App Invite button -} -``` -For more information on Google Sign-In please refer to the [Getting Started Guide][2] - -Displaying the AppInvite UI ---------------------------- - -Once your user is signed in, you can display the AppInvite UI with the following code: - -```csharp -var inviteDialog = Invite.InviteDialog; -inviteDialog.SetInviteDelegate (this); - -// NOTE: You must have the App Store ID set in your developer console project -// in order for invitations to successfully be sent. -var message = string.Format ("Try this out!\n -{0}", - SignIn.SharedInstance.CurrentUser.Profile.Name); - -// A message hint for the dialog. Note this manifests differently depending on the -// received invation type. For example, in an email invite this appears as the subject. -inviteDialog.SetMessage (message); - -// Title for the dialog, this is what the user sees before sending the invites. -inviteDialog.SetTitle ("App Invites Example"); -inviteDialog.SetDeepLink ("app_url"); -inviteDialog.Open (); -``` - -You can should also implement `IInviteDelegate` and optionally the `InviteFinished` method to be notified when the user has completed the AppInvite dialog: - -```csharp -[Export ("inviteFinishedWithInvitations:error:")] -public virtual void InviteFinished (string[] invitationIds, NSError error) -{ - var message = error != null ? error.LocalizedDescription : - string.Format ("{0} invites sent", invitationIds.Length); - - new UIAlertView ("Done", message, null, "OK").Show (); -} -``` - -[1]: https://developers.google.com/mobile/add?platform=ios&cntapi=appinvite -[2]: http://components.xamarin.com/gettingstarted/googleiosappinvite \ No newline at end of file diff --git a/docs/Google/GoogleCloudMessaging/Details.md b/docs/Google/GoogleCloudMessaging/Details.md deleted file mode 100755 index 7e6df8cdf..000000000 --- a/docs/Google/GoogleCloudMessaging/Details.md +++ /dev/null @@ -1,14 +0,0 @@ -Send data from your server to your users' devices, and receive messages from devices on the same connection. The GCM service handles all aspects of queueing of messages and delivery to client applications running on target devices, and it is completely free. - -### Versatile Messaging Targets - -Distribute messages to your client app in any of three ways — to single devices, to groups of devices, or to devices subscribed to topics. - -### Downstream Messaging - -For purposes such as alerting users, chat messaging or kicking off background processing before the user opens the client app, GCM provides a reliable and battery-efficient connection between your server and devices. - -### Upstream Messaging - -Send acknowledgments, chats, and other messages from devices back to your server over GCM’s reliable and battery-efficient connection channel. - diff --git a/docs/Google/GoogleCloudMessaging/GettingStarted.md b/docs/Google/GoogleCloudMessaging/GettingStarted.md deleted file mode 100755 index 9b94d115a..000000000 --- a/docs/Google/GoogleCloudMessaging/GettingStarted.md +++ /dev/null @@ -1,204 +0,0 @@ -Configuring APNS ----------------- - -To allow Google to send APNS notifications on your behalf, you will need to export your Developer and/or your Production APNS certificates from the Apple Developer portal as .p12 files. - -For more information on this process, see [Apple's Documentation][2]. - - - -Configuring your App --------------------- - -Google provides an easy to use configuration web tool to generate a config file for your app: - -1. Open [Google's configuration tool][1] to create a config file for your app. -2. Enter your app's name and iOS Bundle ID and click continue -3. Upload your Developer APNS .p12 certificate. You may also want to upload your production .p12 certificate at this time as well. -3. Click *Enable Cloud Messaging* -4. Click *continue* to generate the configuration files -5. Click *Download Google-Service-Info.plist* -6. Add `GoogleService-Info.plist` to your Xamarin.iOS app project and set the *Build Action* to `BundleResource` -7. Note the *Sender ID* value. You will use this in your code as the `GCM_SENDER_ID` value. - - - -Setting up your AppDelegate ---------------------------- - -Your `AppDelegate` will contain most of the GCM related code. - -In your `FinishedLaunching` method you should start GCM and request to register for remote notifications: - -```csharp -public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) -{ - // Configure and Start GCM - var gcmConfig = Google.GoogleCloudMessaging.Config.DefaultConfig; - gcmConfig.ReceiverDelegate = this; - Service.SharedInstance.Start (gcmConfig); - - // Register for remote notifications - var notTypes = UIUserNotificationType.Sound | UIUserNotificationType.Alert | UIUserNotificationType.Badge; - var settings = UIUserNotificationSettings.GetSettingsForTypes (notTypes, null); - UIApplication.SharedApplication.RegisterUserNotificationSettings (settings); - UIApplication.SharedApplication.RegisterForRemoteNotifications (); - - // Your user code, if any, here - - return true; -} -``` - -Since in the code above the GCM Config's delegate was set to `this` (the AppDelegate), you should also implement `IReceiverDelegate` in your `AppDelegate` class: - -Next, add an override for handling the registration for remote notifications: - -```csharp -public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken) -{ - // Save our token in memory for future calls to GCM - DeviceToken = deviceToken; - - // Configure and start Instance ID - var config = Google.InstanceID.Config.DefaultConfig; - InstanceId.SharedInstance.Start (config); - - // Get a GCM token - GetToken (); -} -``` - -In this method, you will save the `deviceToken` to a variable for later use, as well as configure and start InstanceID which is needed to obtain a GCM Registration Token. - -Finally, this method calls `GetToken()` to actually request a GCM Registration token, which is defined as: - -```csharp -void GetToken () -{ - // Register APNS Token to GCM - var options = new NSDictionary (); - options.SetValueForKey (DeviceToken, Constants.RegisterAPNSOption); - options.SetValueForKey (new NSNumber(true), Constants.APNSServerTypeSandboxOption); - - // Get our token - InstanceId.SharedInstance.Token ( - GCM_SENDER_ID, - Constants.ScopeGCM, - options, - (token, error) => Log ("GCM Registration ID: " + token)); -} -``` - -If the `error` value is null in the callback that was passed into the `Token()` method, you should have a valid GCM Registration token which you will then use on your server to send messages to this device. - - -### Receiving Notifications - -Notifications (both APNS and from GCM) will occur inside of the `DidReceiveRemoteNotification` override. When you receive a message you should inform GCM that you successfully received it: - -```csharp -public override void DidReceiveRemoteNotification (UIApplication application, NSDictionary userInfo, Action completionHandler) -{ - // Your own notification handling logic here - - // Notify GCM we received the message - Service.SharedInstance.AppDidReceiveMessage (userInfo); -} -``` - - - -### Connecting to GCM Servers Directly - -When your application is in the foreground you should connect directly to GCM's servers: - -```csharp -public override void OnActivated (UIApplication application) -{ - Service.SharedInstance.Connect (error => { - if (error != null) - Console.WriteLine ("Could not connect to GCM: {0}", error.LocalizedDescription); - else - Console.WriteLine ("Connected to GCM"); - }); -} -``` - -It's also important to disconnect from the GCM Server when your application enters the background so you can continue to receive APNS notifications instead: - -```csharp -public override void DidEnterBackground (UIApplication application) -{ - Service.SharedInstance.Disconnect (); -} -``` - - -### Unregistering from GCM - -It's possible to unregister from GCM by deleting your token: - -```csharp -public void DeleteToken () -{ - InstanceId.SharedInstance.DeleteToken ( - GCM_SENDER_ID, - Constants.ScopeGCM, - error => { - // Callback, non-null error if there was a problem - if (error != null) - Console.WriteLine ("Deleted Token"); - else - Console.WriteLine ("Error deleting token"); - }); -} -``` - -### Sending Upstream Messages - -One of the advantages to being directly connected to GCM's Servers when your app is in the foreground is the ability to send upstream messages back to the server: - -```csharp -int messageId = 1; - -// We can send upstream messages back to GCM -public void SendUpstreamMessage () -{ - var msg = new NSDictionary (); - msg.SetValueForKey (new NSString ("1234"), new NSString ("userId")); - msg.SetValueForKey (new NSString ("hello world"), new NSString ("msg")); - - var to = GCM_SENDER_ID + "@gcm.googleapis.com"; - - Service.SharedInstance.SendMessage (msg, to, (messageId++).ToString ()); -} -``` - -### Handling Callbacks for Upstream Messages - -Since you implemented `IReceiverDelegate` in your AppDelegate, you can add some methods to be invoked as callbacks for upstream messages: - -```csharp -[Export ("didDeleteMessagesOnServer")] -public void DidDeleteMessagesOnServer () -{ - // ... -} - -[Export ("didSendDataMessageWithID:")] -public void DidSendDataMessage (string messageID) -{ - // ... -} - -[Export ("willSendDataMessageWithID:error:")] -public void WillSendDataMessage (string messageID, NSError error) -{ - // ... -} -``` - - -[1]: https://developers.google.com/mobile/add?platform=ios&cntapi=signin -[2]: https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/ConfiguringPushNotifications/ConfiguringPushNotifications.html \ No newline at end of file diff --git a/docs/Google/InstanceID/Details.md b/docs/Google/InstanceID/Details.md deleted file mode 100755 index 0153bc15b..000000000 --- a/docs/Google/InstanceID/Details.md +++ /dev/null @@ -1,32 +0,0 @@ -Instance ID provides a unique ID per instance of your Android and iOS apps. - -## Key features - -In addition to providing unique IDs for authentication, Instance ID can generate security tokens for use with other services. Other features include: - -### Generate Security Tokens - -Instance ID provides a simple API to generate security tokens that authorize third parties to access your app's server side managed resources. Use these tokens now to authorize push messages for your apps via Google Cloud Messaging. - - -### Confirm app device is active - -The Instance ID server can tell you when the device on which your app is installed was last used. Use this to decide whether to keep data from your app or send a push message to reengage with your users. - - -### Identify and track apps - -Instance ID is unique across all app instances across the world, so your database can use it to uniquely identify and track app instances. Your server-side code can verify, via the Instance ID cloud service, that an Instance ID is genuine and is the same ID as the original app that registered with your server. For privacy, your app can delete an Instance ID so it is no longer associated with any history in the database. The next time your app calls Instance ID it will get an entirely new Instance ID with no relationship to its previous one. - - -## Instance ID lifecycle - -The Instance ID service issues an InstanceID when your app comes online. The InstanceID is backed by a public/private key pair with the private key stored on the local device and the public key registered with the Instance ID service. - -Your app can request a fresh InstanceID whenever needed using the `GetID (..)` method. Your app can store it on your server if you have one that supports your app. - -Your app can request tokens from the Instance ID service as needed using the `GetToken (..)` method, and like InstanceID, your app can also store tokens on your own server. All tokens issued to your app belong to the app's InstanceID. - -Tokens are unique and secure, but your app or the Instance ID service may need to refresh tokens in the event of a security issue or when a user uninstalls and reinstalls your app during device restoration. Your app must implement a listener to respond to token refresh requests from the Instance ID service. - -![InstanceIDLifecycle](https://developers.google.com/instance-id/guides/images/iid-lifecycle.png) \ No newline at end of file diff --git a/docs/Google/InstanceID/GettingStarted.md b/docs/Google/InstanceID/GettingStarted.md deleted file mode 100755 index 40017eba1..000000000 --- a/docs/Google/InstanceID/GettingStarted.md +++ /dev/null @@ -1,29 +0,0 @@ - -## Generating / Fetching an Instance ID - -Before attempting to generate or fetch an Instance ID, you must start the InstanceID engine and pass it an instance of `Config`. You can use the Default instance of `Config`: - -```csharp -InstanceId.SharedInstance.Start (Config.DefaultConfig); -``` - -After you've called `Start (..)`, generating and fetching an InstanceID is done the same way: - -```csharp -var instanceId = await InstanceId.SharedInstance.GetIDAsync (); -``` - -This call may take several seconds to complete, so you should plan on not blocking the UI when making this call. You should always receive the same Instance ID value back after the first time you call this method. - -## Deleting an Instance ID - -It is possible to delete an Instance ID. Once you have deleted a particular Instance ID the next time you call `GetID` or `GetIDAsync` to generate an Instance ID, you will receive a new value. - -To delete an instance ID, simply call `DeleteID` or `DeleteIDAsync`: - -```csharp -await InstanceId.SharedInstance.DeleteIDAsync (); -``` - -**Important Note**: In this version of Instance ID, Google is internally invoking the callback handler that you pass into the `DeleteID` method. They first call back with a non-null error value (error Code 1), and then immediately call back again with a null error, indicating the call succeeded. To work around this, the `DeleteIDAsync` call ignores - \ No newline at end of file diff --git a/docs/Google/PlayGames/Details.md b/docs/Google/PlayGames/Details.md deleted file mode 100755 index 644e5e4d1..000000000 --- a/docs/Google/PlayGames/Details.md +++ /dev/null @@ -1,3 +0,0 @@ -Welcome to iOS game development with Google Play games services! - -The Play Games SDK provides cross-platform Google Play games services that lets you easily integrate popular gaming features such as achievements, leaderboards, and multiplayer to your tablet and mobile games. \ No newline at end of file diff --git a/docs/Google/PlayGames/GettingStarted.md b/docs/Google/PlayGames/GettingStarted.md deleted file mode 100755 index 8844d4662..000000000 --- a/docs/Google/PlayGames/GettingStarted.md +++ /dev/null @@ -1,239 +0,0 @@ -## Add your game to the Google Play Developer Console - -Create an entry for your game in the Google Play Developer Console. This enables Google Play games services for your application, and creates an OAuth 2.0 client ID, if you don't already have one. - -1. Add an entry for your iOS game by following the steps described in [Setting Up Google Play Games Services][1]. -2. Take note of your game's OAuth 2.0 [client ID][2]; you will need this later. -3. (Optional) Add achievements and leaderboards to your game by following the steps described in [Configuring Achievements and Leaderboards][3]. -4. Add accounts for other members of your team to test your game by following the steps described in [Publishing Your Game Changes][4]. - -## Add a sign-in and sign-out button - -In your view controller, add a sign-in button and a sign-out button. Make sure your sign-in button conforms to the [Google+ branding guidelines][5]. To reduce your development effort, many of the built-in user-interfaces provided by Google Play games services already include a sign-out option so you don't need to add this manually. - -```csharp -using Google.Play.GameServices; -... - -const string CLIENT_ID = "123456789012.apps.googleusercontent.com"; - -UIButton signinButton; -UIButton signoutButton; - -public override void ViewDidLoad () -{ - base.ViewDidLoad (); - - signinButton = new UIButton (new CGRect (93, 99, 125, 44)); - signinButton.SetTitle ("Sign In", UIControlState.Normal); - signinButton.TouchUpInside += delegate { - Manager.SharedInstance.SignIn (CLIENT_ID, false); - }; - - signoutButton = new UIButton (new CGRect (93, 299, 125, 44)); - signoutButton.SetTitle ("Sign Out", UIControlState.Normal); - signoutButton.TouchUpInside += delegate { - Manager.SharedInstance.Signout (); - }; - - Add (signinButton); - Add (signoutButton); - -} -``` - -When a player signs in to Google, the sign-in process sends them to the Google+ app, Chrome for iOS, or Mobile Safari (in that sequence). After the player signs in, the app opens a URL that points back to your game and contains the information necessary to complete the sign-in process. Make sure your application can handle the URL that redirects back to your game. Using the options provided in the Google Sign-In SDK, it is possible to selectively enable or disable redirection to Google first-party sign-in apps, Chrome/Safari, or in-app webviews. - -Your app must be setup to accept a URL scheme. You can do this by opening your app's `Info.plist` file, and navigating to the *Advanced* tab. - -In the *URL Types* section, add two *URL Type*s: - -- In one *URL type*, specify a unique string in the Identifier field, and specify your client ID in reversed order in the *URL Schemas* field. For example, if your client ID for iOS is `CLIENT_ID_CODE.apps.googleusercontent.com`, then specify `com.googleusercontent.apps.CLIENT_ID_CODE` in the *URL Schemas* field. -- In the other *URL type*, specify a unique string in the Identifier field, and specify your app's bundle identifier (com.company.appname) in the *URL Schemas* field. - -In your AppDelegate file, add `Google.SignIn` to libraries and override the `OpenUrl` method. This method handles the URL that your application receives at the end of the authentication process: - -```csharp -using Google.SignIn; -... - -public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation) -{ - return SignIn.SharedInstance.HandleUrl (url, sourceApplication, annotation); -} -``` - -In some class of your app (where signin and singout buttons live for example), set `SignIn.SharedInstance.UIDelegate` property: - -```csharp -SignIn.SharedInstance.UIDelegate = this; -``` - -The class assigned to `UIDelegate` property must implement the `ISignInUIDelegate` interface. - -You can now test your application and be able to sign in and out. When testers sign in, they will be redirected to Google+, Chrome, or Safari to complete the sign-in process, and then redirected back to your application. - -## Add a GPGStatusDelegate - -Next, add the code to let your app know that when sign-in process is completed. - -Make a class implements `IStatusDelegate` interface and assign it to `Manager.SharedInstance.StatusDelegate` property. Also, Implement these `IStatusDelegate` methods: `GamesSignInFinished` (to handle completion of player sign-in) and `GamesSignOutFinished` (to handle completion of player sign-out): - -```csharp -public override void ViewDidLoad () -{ - base.ViewDidLoad (); - - Manager.SharedInstance.StatusDelegate = this; -} - -[Export ("didFinishGamesSignInWithError:")] -public void GamesSignInFinished (NSError error) -{ - if (error != null) - Console.WriteLine ("ERROR signing in: {0}", error.LocalizedDescription); - else - Console.WriteLine ("Finished with games sign in!"); - - RefreshYourUI (); -} - - -[Export ("didFinishGamesSignOutWithError:")] -public virtual void GamesSignOutFinished (NSError error) -{ - if (error != null) - Console.WriteLine ("ERROR signing out: {0}", error.LocalizedDescription); - else - Console.WriteLine ("Signed out!"); - - RefreshYourUI (); -} -``` - -After you sign in or you sign out, refresh your UI to determine what button you should show: - -```csharp -void RefreshYourUI () -{ - var signedIn = Manager.SharedInstance.SignedIn; - signinButton.Hidden = signedIn; - signoutButton.Hidden = !signedIn; -} -``` - -Now, when testers finish signing in, the sign-in button will be hidden. When they sign out, the sign-out button will be hidden and the sign-in button should re-appear. - -## Automatically sign in returning players - -You can also sign players in automatically, to avoid having them sign in every time they launch your game. The `Google.Play.GameServices.Manager` will automatically sign the player in when you specify **true** in `Manager.SharedInstance.SignIn` method. This call succeeds if all the following conditions are met: - -- The player has authorized your application in the past; -- The player has not revoked access to your application; and -- The app is not requesting new scopes since the player last signed in. - -Using this behavior, you can sign the player in automatically to your game by adding the `Manager.SharedInstance.SignIn` method to the end of your `ViewDidLoad` method, with silently param (second param) set to **true**. - -```csharp -Manager.SharedInstance.SignIn (CLIENT_ID, true); -``` - -Run your application and notice that, unless you signed out when you last used your application, you are now signed in automatically. - -## Add some interface refinements - -When the application starts player sign-in automatically, there is a small delay between the time sign-in starts and completes. Your game should disable the UI during this time. To do this, use the fact that the `Manager.SharedInstance.SignIn` method returns **true** if it is attempting to sign the player in automatically. You could do something like this: - -``` -using Google.Play.GameServices; -... - -const string CLIENT_ID = "123456789012.apps.googleusercontent.com"; - -UIButton signinButton; -UIButton signoutButton; -bool currentlySigningIn; - -public override void ViewDidLoad () -{ - base.ViewDidLoad (); - - Manager.SharedInstance.StatusDelegate = this; - - signinButton = new UIButton (new CGRect (93, 99, 125, 44)); - signinButton.SetTitle ("Sign In", UIControlState.Normal); - signinButton.TouchUpInside += delegate { - Manager.SharedInstance.SignIn (CLIENT_ID, false); - }; - - signoutButton = new UIButton (new CGRect (93, 299, 125, 44)); - signoutButton.SetTitle ("Sign Out", UIControlState.Normal); - signoutButton.TouchUpInside += delegate { - Manager.SharedInstance.Signout (); - }; - - Add (signinButton); - Add (signoutButton); - - currentlySigningIn = Manager.SharedInstance.SignIn (CLIENT_ID, true); - RefreshYourUI (); -} - -[Export ("didFinishGamesSignInWithError:")] -public void GamesSignInFinished (NSError error) -{ - if (error != null) - Console.WriteLine ("ERROR signing in: {0}", error.LocalizedDescription); - else - Console.WriteLine ("Finished with games sign in!"); - - currentlySigningIn = false; - RefreshYourUI (); -} - - -[Export ("didFinishGamesSignOutWithError:")] -public virtual void GamesSignOutFinished (NSError error) -{ - if (error != null) - Console.WriteLine ("ERROR signing out: {0}", error.LocalizedDescription); - else - Console.WriteLine ("Signed out!"); - - currentlySigningIn = false; - RefreshYourUI (); -} - -void RefreshYourUI () -{ - var signedIn = Manager.SharedInstance.SignedIn; - signinButton.Hidden = signedIn; - signoutButton.Hidden = !signedIn; - - signinButton.Enabled = !currentlySigningIn; - signoutButton.Enabled = !currentlySigningIn; -} -``` - -## More with Play Games - -* [Achievements][6] -* [Leaderboards][7] -* [Saved Games][8] -* [Real-time Multiplayer][9] -* [Turn-based Multiplayer][10] -* [Events and Quests][11] -* [Push Notifications][12] - -[1]: https://developers.google.com/games/services/console/enabling -[2]: https://developers.google.com/games/services/console/enabling#client_id -[3]: https://developers.google.com/games/services/console/configuring#configuring_achievements_and_leaderboards -[4]: https://developers.google.com/games/services/console/testpub#enabling_accounts_for_testing -[5]: https://developers.google.com/+/branding-guidelines -[6]: https://developers.google.com/games/services/ios/achievements -[7]: https://developers.google.com/games/services/ios/leaderboards -[8]: https://developers.google.com/games/services/ios/savedgames -[9]: https://developers.google.com/games/services/ios/realtimeMultiplayer -[10]: https://developers.google.com/games/services/ios/turnbasedMultiplayer -[11]: https://developers.google.com/games/services/ios/quests -[12]: https://developers.google.com/games/services/ios/notifications \ No newline at end of file