prebid / prebid-mobile-ios

Prebid Mobile SDK for iOS applications
Apache License 2.0
48 stars 92 forks source link

Intent to Implement -- Prebid Mobile 1.0 (iOS) #113

Closed mjacobsonny closed 5 years ago

mjacobsonny commented 6 years ago
# Background Prebid Mobile SDKs for iOS and Android were released to GitHub in August 2017 with the intention of providing an end-to-end open-source header bidding solution for mobile app publishers. Over a year of alpha testing, we have worked closely with early adopters to understand major friction points, gaps in understanding, design flaws, and areas for improvement. ## Observations from the Past Year - It is taking publishers far too long to integrate Prebid Mobile - Prebid Mobile has suffered from stability issues - The ad unit creation/ registration/ bid keyword association workflow is too complicated, and is difficult to implement correctly - Interstitial ad units in Prebid Mobile do not work the way that publishers expect - When experiencing issues during implementation, publishers are unable to troubleshoot them effectively # Goals - Simplify Prebid Mobile implementation workflow for publishers - Eliminate inconsistencies between the iOS and Android SDK APIs - Eliminate inconsistencies between DFP and MoPub ad server behavior - Eliminate "secret" backend processes which cause publisher confusion and unexpected behavior - Eliminate Prebid Mobile stability issues and reduce Prebid Mobile bug index # Proposed Design ## Global Settings Global settings will be associated with a `PrebidMobile` object. - `setPrebidServerHost` Define the Prebid Server host with which Prebid Mobile will communicate. Choose from system-defined Prebid Server hosts or define your own custom Prebid Server host. - `setPrebidServerAccountId` Define the Prebid Server account ID provided by your Prebid Server host. - `setShareGeoLocation` Boolean flag. If this flag is True AND the app collects the user's geographical location data, Prebid Mobile will send the user's geographical location data to Prebid Server. If this flag is False OR the app does not collect the user's geographical location data, Prebid Mobile will not populate any user geographical location information in the call to Prebid Server. - `setApplicationContext` For Android only. Prebid Mobile will use the application context to retrieve metadata needed for targeting such as user agent, location, device information, connectivity information, etc. ### Android Example ``` PrebidMobile.setPrebidServerHost(Prebid.Host.APPNEXUS); PrebidMobile.setPrebidServerAccountId("PREBID_SERVER_ACCOUNT_ID"); PrebidMobile.setShareGeoLocation(true); PrebidMobile.setApplicationContext(getApplicationContext()); ``` ### iOS Example ``` let prebidMobile = PrebidMobile() prebidMobile.prebidServerAccountId = "PREBID_SERVER_ACCOUNT_ID" prebidMobile.prebidServerHost = Host.appnexus prebidMobile.shareGeoLocation = true ``` ## Banner Ad Unit - `BannerAdUnit` Create a new Banner Ad Unit associated with a Prebid Server configuration ID and a banner size (width and height). - `addAdditionalSize` Add an additional banner size to the Prebid Mobile ad unit. Banner ad units must be associated with one or more sizes. - `fetchDemand` Trigger a call to Prebid Server to retrieve demand for this Prebid Mobile ad unit. - `addUserKeyword` Add a key-value pair to a given Prebid Mobile ad unit. One key may correspond to one or more values. - `removeUserKeyword` Remove a key and all its associated values from a given Prebid Mobile ad unit. - `clearUserKeywords` Remove all keys and all values from a given Prebid Mobile ad unit. - `setAutoRefreshMillis` If set on a given Prebid Mobile ad unit, the fetchDemand function will be called every periodMillis until stopAutoRefresh is called. Each call to fetchDemand will invoke the onComplete function. - `stopAutoRefresh` Halts the auto-refresh behavior for a given Prebid Mobile ad unit. If no auto-refresh behavior has been set, stopAutoRefresh will be ignored. ### Android Example ``` PublisherAdView dfpAdView = new PublisherAdView(context); dfpAdView.setAdUnitId("/12345/foo"); dfpAdView.setAdSizes(new AdSize(300, 250)); final PublisherAdRequest.Builder builder = new PublisherAdRequest.Builder(); final PublisherAdRequest request = builder.build(); BannerAdUnit bannerAdUnit = new BannerAdUnit("PREBID_SERVER_CONFIGURATION_ID", 300, 250); bannerAdUnit.addUserKeyword("my_key", "my_value"); bannerAdUnit.fetchDemand(request, new onCompleteListener() { @Override public void onComplete(ResultCode resultCode) { dfpAdView.loadAd(request); } }); ``` ### iOS Example ``` var dfpBannerView = DFPBannerView(adSize: GADAdSizeFromCGSize(CGSize(width: 300, height: 250))) dfpBannerView.adUnitID = "/12345/foo" dfpBannerView.rootViewController = self; dfpBannerView.delegate = self let bannerAdUnit = BannerAdUnit(configId: "PREBID_SERVER_CONFIGURATION_ID", size: CGSize(width: 300, height: 250)) bannerAdUnit.addUserKeyword(key: "my_key", value: "my_value") bannerAdUnit.fetchDemand(adObject: dfpBannerView) { (resultCode) in //Load the dfp request dfpBannerView.load(GADRequest()) } ``` ## Interstitial Ad Unit - `InterstitialAdUnit` Create a new Interstitial Ad Unit associated with a Prebid Server configuration ID. - `fetchDemand` Trigger a call to Prebid Server to retrieve demand for this Prebid Mobile ad unit. - `addUserKeyword` Add a key-value pair to a given Prebid Mobile ad unit. One key may correspond to one or more values. - `removeUserKeyword` Remove a key and all its associated values from a given Prebid Mobile ad unit. - `clearUserKeywords` Remove all keys and all values from a given Prebid Mobile ad unit. - `setAutoRefreshMillis` If set on a given Prebid Mobile ad unit, the fetchDemand function will be called every periodMillis until stopAutoRefresh is called. Each call to fetchDemand will invoke the onComplete function. - `stopAutoRefresh` Halts the auto-refresh behavior for a given Prebid Mobile ad unit. If no auto-refresh behavior has been set, stopAutoRefresh will be ignored. ### Android Example ``` InterstitialAdUnit interstitialAdUnit = new InterstitialAdUnit("PREBID_SERVER_CONFIGURATION_ID"); interstitialAdUnit.addUserKeyword("my_key", "my_value"); interstitialAdUnit.fetchDemand(publisherAdRequest, new onCompleteListener() { @Override public void onComplete(ResultCode resultCode) { dfpInterstitial.loadAd(publisherAdRequest); } }); ``` ### iOS Example ``` let dfpInterstitialView = DFPInterstitial(adUnitID: "/12345/foo") dfpInterstitialView.delegate = self let interstitialAdUnit = InterstitialAdUnit(configId: "PREBID_SERVER_CONFIGURATION_ID") interstitialAdUnit.addUserKeyword(key: "my_key", value: "my_value") interstitialAdUnit.fetchDemand(adObject: dfpInterstitialView) { (resultCode) in //Load the dfp request interstitialAdUnit.load(GADRequest()) } ``` ## Result Codes - Success Prebid Mobile received at least one valid bid from Prebid Server and successfully associated Prebid key-values with the appropriate ad server request. - Prebid Server Error General result code for an unknown error returned from Prebid Server. The actual Prebid Server error message will be exposed to the developer. - Invalid account ID Prebid Server did not recognize the account ID. - Invalid configuration ID Prebid Server did not recognize the configuration ID. - Invalid size Attempted to add an invalid size to a banner ad unit. - Network error Request to Prebid Server resulted in a network error. - Timeout Request to Prebid Server resulted in a timeout. - No bids Prebid Server responded without returning any valid bids. - Empty host URL Attempted to define a custom Prebid Server host without providing a host URL. - Invalid ad object Ad object passed to `fetchDemand` is not supported. ## Global Targeting Parameters Prebid Mobile will support the following global targeting parameters. These targeting parameters are set only once and apply to all Prebid Mobile ad units. They do not change for a given user session. ### Global User Targeting - Year of birth - Gender ### Global Application Targeting - Bundle ID - Domain - Store URL ### Global GDPR Targeting - Flag to indicate if the user is subject to GDPR - GDPR consent string
AntoineJac commented 6 years ago

Hi @mjacobsonny ,

Thanks so no major changes require on client side but will imply some updates on Prebid Server as it will expect to return some success or error codes that will be handle by the client SDK. We need to make sure the new ad response are still compliant and won't break the old SDK version.

Here are also a few missing points that would be also nice to have in future:

  • add an analytics module in Prebid so a bidder could register to some event (adUnits call, timeout...)
  • no video feature, have we planned to propose any instream or outstream format?
  • add an option in "PrebidMobile" to select client or server side caching (and push the fix for ios caching)

Thanks,

mjacobsonny commented 6 years ago

Hey @AntoineJac -- Thank you for the feedback! I've added your bullets below with some responses in-line:

Add an analytics module in Prebid so a bidder could register to some event (adUnits call, timeout...)

This is an interesting idea, but would we want these "analytics modules" to live in Prebid Mobile or in Prebid Server? Do you have a proposal for what this might look like?

No video feature, have we planned to propose any instream or outstream format?

Video will not be in focus for Prebid Mobile 1.0.0, but we do have plans to add video support in a subsequent minor version release.

Add an option in "PrebidMobile" to select client or server side caching (and push the fix for ios caching)

Ideally, I would like all of the caching behavior to be abstracted away from the end-publisher and to keep the publisher-facing API as simple as possible. If we learn of a compelling use-case to add this type of functionality, we would have to think carefully about the implementation, as our previous attempt to enable client-side caching caused substantial confusion and SDK instability.

AntoineJac commented 6 years ago

Hi @mjacobsonny , thanks a lot. Here are a few response to your points.

1- Analytics: Most of the events and data will indeed be supported by Prebid Server but it is not perfect as client side data won't be tracked. There is currently no official decision to track these client events or not but I guess it is a feature we should thing about.

2- caching: Yes I guess this settings should be indeed control by prebid server instead of checking the presence of requestPrebidExt[@"cache"] = @{@"bids"}.

However I would still at least suggest:

  • making server caching by default on iOS and android
  • pushing my fix for the local caching on iOS

Do notice that currently android is using local caching by default and only way to use server caching is doing: Field useLocalCache = Prebid.class.getDeclaredField("useLocalCache"); useLocalCache.setAccessible(true); useLocalCache.set(null, false);

AntoineJac commented 5 years ago

Hi @mjacobsonny , first happy new year! ;)

Just to follow up on this, I would also like to stop relying on swizzling technique on 3rd party SDK (Google SDK's or Mopub). It is a dangerous practise behaviour in case on of the class or method we are swizzling is edited (that happened with GadSlot fixed in v0.5.3). Some publisher may also use a SDK rewriting the SDK api already. There is a workaround by directly remove the swizzle and use the following code as setBidKeywordsOnAdObject completionHandler but I would prefer having an official way:

        DFPRequest *request = [DFPRequest request];
        SEL getPb_identifier = NSSelectorFromString(@"pb_identifier");
        if ([self.dfpAdView respondsToSelector:getPb_identifier])
        {
            PBAdUnit *adUnit = (PBAdUnit *)[self.dfpAdView performSelector:getPb_identifier];
            NSDictionary<NSString * , NSString *> *keywordsPairs = [[PBBidManager sharedInstance] keywordsForWinningBidForAdUnit:adUnit];

            request.customTargeting = keywordsPairs;
        }
        [self.dfpAdView loadRequest:request];
        [[PBBidManager sharedInstance] clearBidOnAdObject:self.dfpAdView];
lilahunt commented 5 years ago

Re. analytics - we are discussing extensively in the Prebid Mobile PMC and agree as much as possible should live in prebid server. If you have a list of the client side events that should also be tracked we would like to capture in our Mobile roadmap as well. We have discussed the win notifications potentially being sent back to prebid server so an analytics solution only has to interface with Server rather than SDK adapters. Let me know you if would be interested in joining a conversation with us on this topic :)

AntoineJac commented 5 years ago

@lilahunt , thanks for the details. Indeed having only one source handling all the analytics sound better and should work fine with a notification return to prebid server. 👍

lilahunt commented 5 years ago

This version was released. We are on V1.1. Closing.