In-App Event

Pelajari cara bekerja dengan in-app event di iOS SDK.

Overview

Dokumen ini adalah panduan tentang penerapan in-app event di iOS SDK. Sebagai pengantar in-app event bagi programmer, lihat In-app event.

Sebelum Anda memulai:

Anda harus mengintegrasikan SDK .

Mencatat in-app event

SDK memungkinkan Anda mencatat tindakan pengguna yang terjadi dalam konteks aplikasi Anda. Ini biasanya disebut sebagai in-app event .

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 membutuhkan 3 argumen:

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

📘

Catatan

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

Example: Send "add to wishlist" event

Misalnya, untuk mencatat bahwa pengguna menambahkan item ke wishlist mereka:

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

Berdasarkan contoh definisi yang diberikan dalam Memahami definisi struktur event , event tersebut harus diterapkan sebagai berikut:

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

  • In-app event berhasil dicatat.
  • Terjadi kesalahan saat mencatat in-app event.
[[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)
            }
          });

Jika terjadi kesalahan saat merekam in-app event, muncul kode kesalahan dan deskripsi string, seperti yang ditunjukkan pada tabel berikut.

Kode ErrorDeskripsi (NSError)
10"Event timeout (batas waktu event). Periksa parameter 'minTimeBetweenSessions'"
11"Skipping event because 'isStopTracking' enabled" (Lewati event karena 'isStopTracking' diaktifkan)
40Network error: Error description comes from iOS
41"No dev key" (tidak ada kode pengembang)
50"Status code failure" (kode status gagal)+ kode respons aktual dari server

Recording offline events

SDK dapat merekam event yang terjadi saat tidak ada koneksi internet yang tersedia. Lihat In-app event offline untuk rinciannya.

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.

Jika ada beberapa event dalam cache, event ini dikirim ke server satu per satu (tidak di-batch, satu permintaan jaringan per event).

📘

Catatan

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

Mencatat pendapatan

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.

Nilai pendapatan tidak boleh mengandung pemisah koma, simbol mata uang, atau teks. Misalnya, event pendapatan harus serupa dengan 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"
]);

📘

Catatan

Jangan menambahkan simbol mata uang ke nilai pendapatan.

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

Untuk mempelajari tentang pengaturan mata uang, tampilan, dan konversi mata uang, lihat panduan tentang mata uang pendapatan.

Logging negative revenue

Mungkin ada situasi di mana Anda ingin mencatat pendapatan negatif. Misalnya, pengguna menerima pengembalian dana atau membatalkan berlangganan.

Untuk mencatat pendapatan negatif:

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

Pada kode di atas, perhatikan beberapa hal berikut:

  • Nilai pendapatan didahului dengan tanda minus
  • 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

Memvalidasi pembelian

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

📘

Catatan

The legacy function validateAndLogInAppPurchase can be replaced by the newer and fully automatic purchase SDK connector. To learn how to integrate the connector, see in Github iOS purchase SDK connector

Purchase validation using validateAndLogInAppPurchase

validateAndLoginInAppPurchase mengambil argumen ini:

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

📘

Catatan

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

Menguji validasi pembelian dalam mode Sandbox

Untuk menguji validasi pembelian menggunakan lingkungan sandbox, tambahkan kode berikut:

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

📘

Catatan

Kode ini harus dihapus dari build produksi Anda.

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
}

Konstanta event

Predefined event names

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

eventNameNama konstanta 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.

Nama parameter eventNama konstanta iOSJenis
"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