In-app события

Узнайте, как работать с внутренними событиями приложений в iOS SDK.

Обзор

Этот документ представляет собой руководство по реализации внутренних событий приложения в iOS SDK. Общие сведения о внутренних событиях для разработчиков см. в статье Внутренние события приложения.

Прежде чем начать

Необходимо интегрировать SDK.

Регистрация внутренних событий приложения

SDK позволяет регистрировать действия пользователей в контексте приложения. Такие действия обычно называют внутренними событиями приложения.

The logEvent method

The logEvent method lets you log in-app events and send them to AppsFlyer for processing.

AppsFlyerLib exposes logEvent, predefined event name constants and predefined event parameter constants.

logEvent принимает три аргумента:

- (void)logEventWithEventName:(NSString *)eventName
        eventValues:(NSDictionary<NSString * , id> * _Nullable)eventValues
        completionHandler:(void (^ _Nullable)(NSDictionary<NSString *, id> * _Nullable dictionary, NSError * _Nullable error))completionHandler;
  • The first argument (eventName) is the event name
  • The second argument (eventValues) is the event parameters NSDictionary
  • The third argument (completionHandler) is an optional completion handler (useful for Handling event submission success/failure)

📘

Примечание

eventValues (second argument) must be a valid NSDictionary. For more information, see Foundation JSONSerialization.

Example: Send "add to wishlist" event

Например, чтобы зарегистрировать, что пользователь добавил товар в список желаний:

[[AppsFlyerLib shared]  logEvent: AFEventAddToWishlist withValues: @{
    AFEventParamPrice: @20,
    AFEventParamContentId: @"123456"
}]
AppsFlyerLib.shared().logEvent(AFEventAddToWishlist,
  withValues: [
     AFEventParamPrice: 20,
     AFEventParamContentId: "123456"
]);

In the above logEvent invocation:

  • Имя события AFEventAddToWishlist
  • The event value is a NSDictionary containing these event parameters:
    • AFEventParamPrice: цена товара, добавленного пользователем в список желаний.
    • AFEventParamContentId: идентификатор добавленного товара.

Implementing in-app event definitions

На основе примера определения из раздела Определение структуры событий, событие следует реализовать следующим образом:

[[AppsFlyerLib shared]  logEvent: AFEventContentView withValues: @{
    AFEventParamContentId: <ITEM_SKU>,
    AFEventParamContentType: <ITEM_TYPE>,
    AFEventParamPrice: <ITEM_PRICE>
}]
AppsFlyerLib.shared().logEvent(AFEventAddToCart,
  withValues: [
    AFEventParamContent: <ITEM_NAME>
    AFEventParamContentId: <ITEM_SKU>
    AFEventParamPrice: <ITEM_PRICE>
]);

Handling event submission success and failure

You can pass a completionHandler to logEvent when recording in-app events. The handler allows you to define logic for two scenarios:

  • Внутреннее событие приложения зарегистрировано успешно.
  • При регистрации внутреннего события произошла ошибка.
[[AppsFlyerLib shared] logEventWithEventName:AFEventPurchase
        eventValues: @{
          AFEventParamRevenue: @200,
          AFEventParamCurrency: @"USD",
          AFEventParamQuantity: @2,
          AFEventParamContentId: @"092",
          AFEventParamReceiptId: @"9277"
        }
        completionHandler:^(NSDictionary<NSString *,id> * _Nullable dictionary, NSError * _Nullable error){
            if(dictionary != nil) {
                NSLog(@"In app callback success:");
                for(id key in dictionary){
                    NSLog(@"Callback response: key=%@ value=%@", key, [dictionary objectForKey:key]);
                }
            }
            if(error != nil) {
                NSLog(@"In app callback error:", error);
            }
    }];
AppsFlyerLib.shared().logEvent(name: AFEventAddToWishlist,
          values: [
             AFEventParamPrice: 20,
             AFEventParamContentId: "123456"
          ],
          completionHandler: { (response: [String : Any]?, error: Error?) in
            if let response = response {
              print("In app event callback Success: ", response)
            }
            if let error = error {
              print("In app event callback ERROR:", error)
            }
          });

В случае возникновения ошибки во время записи внутреннего события отображается код ошибки и описание строки, как указано в таблице ниже.

Код ошибкиОписание (NSError)
10"Event timeout. Check 'minTimeBetweenSessions' param" («Время события истекло. Проверьте параметр minTimeBetweenSessions»)
11"Skipping event because 'isStopTracking' enabled" («Событие пропущено, т. к. включен параметр isStopTracking»)
40Network error: Error description comes from iOS
41"No dev key" («Нет ключа разработчика»)
50"Status code failure" («Ошибка кода статуса») + фактический код ответа от сервера

Recording offline events

SDK может регистрировать события, которые произошли без подключения к интернету. См. статью Внутренние события приложения в режиме офлайн.

Logging events before calling start

If you initialized the SDK but didn't call start, the SDK will cache in-app events until start is invoked.

Если в кэше хранится несколько событий, они отправляются на сервер одно за другим (без пакетирования, один сетевой запрос на событие).

📘

Примечание

If the SDK is initialized, logEvent invocations will call SKAdNetwork's updateConversionValue even if start wasn't called or isStopped is set to true (in both SDK and S2S modes).

Регистрация дохода

af_revenue is the only event parameter that AppsFlyer counts as real revenue in the dashboard and reports.
You can send revenue with any in-app event. Use the AFEventParameterRevenue constant to include revenue in the in-app event. You can populate it with any numeric value, positive or negative.

В значениях дохода нельзя использовать запятые-разделители, знаки валюты или текст. Событие дохода должно иметь, например, такой формат: 1234.56.

Example: Purchase event with revenue

[[AppsFlyerLib shared] logEvent: AFEventPurchase 
withValues:@{
	AFEventParamContentId:@"1234567",
	AFEventParamContentType : @"category_a",
	AFEventParamRevenue: @200,
	AFEventParamCurrency:@"USD"
}];
AppsFlyerLib.shared().logEvent(AFEventPurchase, 
withValues: [
	AFEventParamContentId:"1234567",
	AFEventParamContentType : "category_a",
	AFEventParamRevenue: 200,
	AFEventParamCurrency:"USD"
]);

📘

Примечание

Не добавляйте символы валюты в значение дохода.

Configuring revenue currency

You can set the currency code for an event's revenue by using the af_currency predefined event parameter:

[[AppsFlyerLib shared] logEvent: AFEventPurchase
withValues:@{
	AFEventParamRevenue: @200,
	AFEventParamCurrency:@"USD"
}];
AppsFlyerLib.shared().logEvent(AFEventPurchase, 
withValues: [
	AFEventParamRevenue: 200,
	AFEventParamCurrency:"USD"
]);
  • Код валюты должен быть кодом из трех символов по стандарту ISO 4217
  • Валюта по умолчанию: USD

Сведения о настройках валюты, отображении и конвертации валюты см. в нашем справочнике по валюте доходов.

Logging negative revenue

Возможны такие ситуации, когда нужно зарегистрировать отрицательный доход. Пример: пользователь приложения получает возмещение или отменяет подписку.

Чтобы регистрировать отрицательную выручку:

[[AppsFlyerLib shared] logEvent: @"cancel_purchase" 
withValues:@{
	AFEventParamContentId:@"1234567",
	AFEventParamContentType : @"category_a",
	AFEventParamRevenue: @-1.99,
	AFEventParamCurrency:@"USD"
}];
AppsFlyerLib.shared().logEvent("cancel_purchase", 
withValues: [
	AFEventParamContentId:"1234567",
	AFEventParamContentType : "category_a",
	AFEventParamRevenue: -1.99,
	AFEventParamCurrency:"USD"
]);

Обратите внимание на приведенный выше код:

  • Перед значением дохода стоит знак минус
  • The event name is a custom event called cancel_purchase - that's how the marketer identifies negative revenue events in the dashboard and raw-data reports

Проверка покупок

AppsFlyer provides server verification for in-app purchases. The validateAndLogInAppPurchase method takes care of validating and logging the purchase event.

📘

Примечание

Устаревшую функцию validateAndLogInAppPurchase можно заменить более новым и полностью автоматическим коннектором SDK для покупок. Чтобы узнать, как интегрировать коннектор, смотрите статью на Github Коннектор SDK для измерения дохода от покупок на iOS

Purchase validation using validateAndLogInAppPurchase

validateAndLoginInAppPurchase принимает следующие аргументы:

- (void) validateAndLogInAppPurchase:(NSString *) productIdentifier,
                  price:(NSString *) price
                  currency:(NSString *) currency
                  transactionId:(NSString *) tranactionId
                  additionalParameters:(NSDictionary *) params
                  success:(void (^)(NSDictionary *response)) successBlock
                  failure:(void (^)(NSError *error, id reponse)) failedBlock;
validateAndLog(inAppPurchase: String?,
               price: String?,
               currency: String?,
               transactionId: String?,
               additionalParameters: [AnyHashable : Any]?,
               success: ([AnyHashable : Any]) -> Void)?,
               failure: ((Error?, Any?) -> Void)?)

Upon successful validation, a NSDictionary is returned with the receipt validation data (provided by Apple servers).

📘

Примечание

Calling validateAndLogInAppPurchase generates an af_purchase in-app event upon successful validation. Sending this event yourself creates duplicate event reporting.

Example: Validate in-app purchase

[[AppsFlyerLib shared] validateAndLogInAppPurchase:@"ProductIdentifier" price:@"price"
    currency:@"USD"
    transactionId:@"transactionID"
    additionalParameters:@{@"test": @"val" , @"test1" : @"val 1"}
    success:^(NSDictionary *result){
      NSLog(@"Purchase succeeded And verified! response: %@", result[@"receipt"]);
    } failure:^(NSError *error, id response) {
      NSLog(@"response = %@", response);
      if([response isKindOfClass:[NSDictionary class]]) {
        if([response[@"status"] isEqualToString:@"in_app_arr_empty"]){
          // retry with 'SKReceiptRefreshRequest' because
          // Apple has returned an empty response
          // <YOUR CODE HERE>
        }

      } else {
        //handle other errors
        return;
      }
  }];
AppsFlyerLib.shared().validateAndLogInAppPurchase (
  inAppPurchase: "productIdentifier",
  price: "price",
  currency: "currency",
  transactionId: "transactionId",
  additionalParameters: [:],
  success: {
      guard let dictionary = $0 as? [String:Any] else { return }
      dump(dictionary)
    }, 
  failure: { error, result in
      guard let emptyInApp = result as? [String:Any],
      let status = emptyInApp["status"] as? String,
      status == "in_app_arr_empty" else {
      // Try to handle other errors
      return
    }     
    })

Тестирование проверки покупки в безопасной среде

Чтобы протестировать проверку покупки в безопасной среде, добавьте следующий код:

[AppsFlyerLib shared].useReceiptValidationSandbox = YES;
AppsFlyerLib.shared().useReceiptValidationSandbox = true

📘

Примечание

Этот код необходимо удалить из ваших рабочих сборок.

Validating an in-app purchase automatically generates and sends an in-app purchase event to AppsFlyer. Its eventValues will look something like this:

{
   "some_parameter": "some_value", // from additional_event_values
   "af_currency": "USD", // from currency
   "af_content_id" :"test_id", // from purchase
   "af_revenue": "10", // from revenue
   "af_quantity": "1", // from purchase
   "af_validated": true // flag that AF verified the purchase
}

Константы событий

Predefined event names

Predefined event name constants follow a AFEventEventName naming convention. For example, AFEventAddToCart.

Имя событияИмя константы iOS
"af_level_achieved"
AFEventLevelAchieved
"af_add_payment_info"
AFEventAddPaymentInfo
"af_add_to_cart"
AFEventAddToCart
"af_add_to_wishlist"
AFEventAddToWishlist
"af_complete_registration"
AFEventCompleteRegistration
"af_tutorial_completion"
AFEventTutorial_completion
"af_initiated_checkout"
AFEventInitiatedCheckout
"af_purchase"
AFEventPurchase
"af_rate"
AFEventRate
AFEventSearch
"af_spent_credits"
AFEventSpentCredits
"af_achievement_unlocked"
AFEventAchievementUnlocked
"af_content_view"
AFEventContentView
"af_list_view"
AFEventListView
"af_travel_booking"
AFEventTravelBooking
"af_share"
AFEventShare
"af_invite"
AFEventInvite
"af_login"
AFEventLogin
"af_re_engage"
AFEventReEngage
"af_update"
AFEventUpdate
"af_opened_from_push_notification"
AFEventOpenedFromPushNotification
"af_location_coordinates"
AFEventLocation
"af_customer_segment"
AFEventCustomerSegment
"af_subscribe"
AFEventSubscribe
"af_start_trial"
AFEventStartTrial
"af_ad_click"
AFEventAdClick
"af_ad_view"
AFEventAdView

Predefined event parameters

Predefined event parameter constants follow a AFEventParamParameterName naming convention. For example, AFEventParamRevenue.

Имя параметра событияИмя константы iOSТип
"af_content"
AFEventParamContentString
"af_achievement_id"
AFEventParamAchievementIdString
"af_level"
AFEventParamLevelString
"af_score"
AFEventParamScoreString
"af_success"
AFEventParamSuccessString
"af_price"
AFEventParamPricefloat
"af_content_type"
AFEventParamContentTypeString
"af_content_id"
AFEventParamContentIdString
"af_content_list"
AFEventParamContentListString[]
"af_currency"
AFEventParamCurrencyString
"af_quantity"
AFEventParamQuantityint
"af_registration_method"
AFEventParamRegistrationMethodString
"af_payment_info_available"
AFEventParamPaymentInfoAvailableString
"af_max_rating_value"
AFEventParamMaxRatingValueString
"af_rating_value"
AFEventParamRatingValueString
"af_search_string"
AFEventParamSearchStringString
"af_date_a"
AFEventParamDateAString
"af_date_b"
AFEventParamDateBString
"af_destination_a"
AFEventParamDestinationAString
"af_destination_b"
AFEventParamDestinationBString
"af_description"
AFEventParamDescriptionString
"af_class"
AFEventParamClassString
"af_event_start"
AFEventParamEventStartString
"af_event_end"
AFEventParamEventEndString
"af_lat"
AFEventParamLatString
"af_long"
AFEventParamLongString
"af_customer_user_id"
AFEventParamCustomerUserIdString
"af_validated"
AFEventParamValidatedboolean
"af_revenue"
AFEventParamRevenuefloat
"af_projected_revenue"
AFEventProjectedParamRevenuefloat
"af_receipt_id"
AFEventParamReceiptIdString
"af_tutorial_id"
AFEventParamTutorialIdString
"af_virtual_currency_name"
AFEventParamVirtualCurrencyName
AFEventParamDeepLinkString
"af_old_version"
AFEventParamOldVersionString
"af_new_version"
AFEventParamNewVersionString
"af_review_text"
AFEventParamReviewTextString
"af_coupon_code"
AFEventParamCouponCodeString
"af_order_id"
AFEventParamOrderIdString
"af_param_1"
AFEventParam1String
"af_param_2"
AFEventParam2String
"af_param_3"
AFEventParam3String
"af_param_4"
AFEventParam4String
"af_param_5"
AFEventParam5String
"af_param_6"
AFEventParam6String
"af_param_7"
AFEventParam7String
"af_param_8"
AFEventParam8String
"af_param_9"
AFEventParam9String
"af_param_10"
AFEventParam10String
"af_departing_departure_date"
AFEventParamDepartingDepartureDateString
"af_returning_departure_date"
AFEventParamReturningDepartureDateString
"af_destination_list"
AFEventParamDestinationListString[]
"af_city"
AFEventParamCityString
"af_region"
AFEventParamRegionString
"af_country"
AFEventParamCountryString
"af_departing_arrival_date"
AFEventParamDepartingArrivalDateString
"af_returning_arrival_date"
AFEventParamReturningArrivalDateString
"af_suggested_destinations"
AFEventParamSuggestedDestinationsString[]
"af_travel_start"
AFEventParamTravelStartString
"af_travel_end"
AFEventParamTravelEndString
"af_num_adults"
AFEventParamNumAdultsString
"af_num_children"
AFEventParamNumChildrenString
"af_num_infants"
AFEventParamNumInfantsString
"af_suggested_hotels"
AFEventParamSuggestedHotelsString[]
"af_user_score"
AFEventParamUserScoreString
"af_hotel_score"
AFEventParamHotelScoreString
"af_purchase_currency"
AFEventParamPurchaseCurrencyString
"af_preferred_neighborhoods"
AFEventParamPreferredNeighborhoods //array of stringString[]
"af_preferred_num_stops"
AFEventParamPreferredNumStopsString
"af_adrev_ad_type"
AFEventParamAdRevenueAdTypeString
"af_adrev_network_name"
AFEventParamAdRevenueNetworkNameString
"af_adrev_placement_id"
AFEventParamAdRevenuePlacementIdString
"af_adrev_ad_size"
AFEventParamAdRevenueAdSizeString
"af_adrev_mediated_network_name"
AFEventParamAdRevenueMediatedNetworkNameString
"af_preferred_price_range"
AFEventParamPreferredPriceRangeint[] - basically a tuple(min,max) but we'll use array of int and use two values
"af_preferred_star_ratings"
AFEventParamPreferredStarRatingsint[] - basically a tuple(min,max) but we'll use array of int and use two values