Eventos in-app

Saiba como trabalhar com eventos in-app no SDK do iOS.

Visão Geral

Este documento é um guia sobre a implementação de eventos in-app no SDK para iOS. Para obter uma introdução aos eventos in-app para desenvolvedores, consulte eventos in-app.

Antes de começar

Você deve integrar o SDK.

Registrando eventos in-app

O SDK permite registrar ações do usuário que acontecem no contexto do aplicativo. Eles geralmente são chamados de eventos in-app.

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 leva 3 argumentos:

- (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)

📘

Observação

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

Example: Send "add to wishlist" event

Por exemplo, para registrar que um usuário adicionou um item à lista de desejos:

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

In the above logEvent invocation:

Implementing in-app event definitions

Com base na definição de exemplo fornecida em Compreendendo as definições da estrutura de eventos, o evento deve ser implementado da seguinte forma:

[[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:

  • Um evento in-app gravado com sucesso
  • Ocorreu um erro ao gravar o evento in-app
[[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)
            }
          });

Se um erro ocorrer ao gravar o evento in-app, um código de erro e uma descrição de string são fornecidos, conforme indicado na tabela a seguir.

Código do erroDescrição (NSError)
10"Event timeout. Check 'minTimeBetweenSessions' param" ("Tempo limite do evento. Verifique parâmetro 'minTimeBetweenSessions'")
11"Skipping event because 'isStopTracking' enabled" ("Ignorando evento porque 'IsStopTracking' está ativado")
40Network error: Error description comes from iOS
41"No dev key" ("Sem chave do desenvolvedor")
50"Falha no código de status" + código de resposta real do servidor

Recording offline events

O SDK pode registrar eventos que ocorrem quando nenhuma conexão com a internet está disponível. Consulte Eventos in-app offline para obter detalhes.

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.

Se houver vários eventos no cache, eles serão enviados para o servidor um após o outro (sem lote, uma solicitação de rede por evento).

📘

Observação

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).

Registro de receita

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.

O valor da receita não deve conter separadores de vírgula, símbolo de moeda ou texto. Um evento de receita deve ser semelhante a 1234,56, por exemplo.

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"
]);

📘

Observação

Não adicione símbolos de moeda ao valor da receita.

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"
]);
  • O código da moeda deve ser um código ISO 4217 de 3 caracteres
  • A moeda padrão é USD

Para saber mais sobre configurações de moeda, exibição e conversão de moeda, consulte nosso guia sobre moeda de receita.

Logging negative revenue

Pode haver situações em que você deseja registrar receita negativa. Por exemplo, um usuário recebe um reembolso ou cancela uma assinatura.

Para registrar a receita negativa:

[[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"
]);

Observe o seguinte no código acima:

  • O valor da receita é precedido por um sinal de menos
  • 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

Validando compras

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

📘

Observação

A função legada validateAndLogInAppPurchasepode ser substituída pelo conector SDK de compra mais recente e totalmente automático. Para saber como integrar o conector, veja o conector do SDK de compra do iOS no Github

Purchase validation using validateAndLogInAppPurchase

validateAndLoginInAppPurchase pega esses argumentos:

- (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).

📘

Observação

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
    }     
    })

Testando a validação de compra no modo Sandbox

Para testar a validação de compra usando um ambiente de área restrita, adicione o seguinte código:

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

📘

Observação

Esse código deve ser removido de suas compilações de produção.

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
}

Constantes de eventos

Predefined event names

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

Nome do eventoNome da constante do 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.

Nome do parâmetro do eventoNome da constante do iOSTipo
"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