kandi background
Explore Kits

butterknife | Bind Android views and callbacks to fields and methods. | Android library

 by   JakeWharton Java Version: Current License: Apache-2.0

 by   JakeWharton Java Version: Current License: Apache-2.0

Download this library from

kandi X-RAY | butterknife Summary

butterknife is a Java library typically used in Mobile, Android applications. butterknife has no vulnerabilities, it has build file available, it has a Permissive License and it has high support. However butterknife has 6 bugs. You can download it from GitHub.
Attention: This tool is now deprecated. Please switch to [view binding](https://developer.android.com/topic/libraries/view-binding). Existing versions will continue to work, obviously, but only critical bug fixes for integration with AGP will be considered. Feature development and general bug fixes have stopped. Field and method binding for Android views which uses annotation processing to generate boilerplate code for you. For documentation and additional information see [the website][3].
Support
Support
Quality
Quality
Security
Security
License
License
Reuse
Reuse

kandi-support Support

  • butterknife has a highly active ecosystem.
  • It has 25707 star(s) with 4748 fork(s). There are 1093 watchers for this library.
  • It had no major release in the last 12 months.
  • There are 95 open issues and 1065 have been closed. On average issues are closed in 83 days. There are 19 open pull requests and 0 closed requests.
  • It has a positive sentiment in the developer community.
  • The latest version of butterknife is current.
butterknife Support
Best in #Android
Average in #Android
butterknife Support
Best in #Android
Average in #Android

quality kandi Quality

  • butterknife has 6 bugs (0 blocker, 0 critical, 0 major, 6 minor) and 516 code smells.
butterknife Quality
Best in #Android
Average in #Android
butterknife Quality
Best in #Android
Average in #Android

securitySecurity

  • butterknife has no vulnerabilities reported, and its dependent libraries have no vulnerabilities reported.
  • butterknife code analysis shows 0 unresolved vulnerabilities.
  • There are 0 security hotspots that need review.
butterknife Security
Best in #Android
Average in #Android
butterknife Security
Best in #Android
Average in #Android

license License

  • butterknife is licensed under the Apache-2.0 License. This license is Permissive.
  • Permissive licenses have the least restrictions, and you can use them in most projects.
butterknife License
Best in #Android
Average in #Android
butterknife License
Best in #Android
Average in #Android

buildReuse

  • butterknife releases are not available. You will need to build from source code and install.
  • Build file is available. You can build the component from source.
  • Installation instructions, examples and code snippets are available.
  • butterknife saves you 6962 person hours of effort in developing the same functionality from scratch.
  • It has 14424 lines of code, 706 functions and 187 files.
  • It has low code complexity. Code complexity directly impacts maintainability of the code.
butterknife Reuse
Best in #Android
Average in #Android
butterknife Reuse
Best in #Android
Average in #Android
Top functions reviewed by kandi - BETA

kandi has reviewed butterknife and discovered the below as its top functions. This is intended to give you an instant insight into butterknife implemented functionality, and help decide if they suit your requirements.

  • Parse a listener annotation .
    • Adds the method bindings to the result .
      • Create a new argument transformer .
        • Get a drawable for a specific resource id .
          • Gets the required bindings .
            • Override in order to set the activity s fields .
              • Handle a click event .
                • Generate code block
                  • Unbinds all bindings .
                    • Runs the given actions on the given list .

                      Get all kandi verified functions for this library.

                      Get all kandi verified functions for this library.

                      butterknife Key Features

                      Eliminate findViewById calls by using @BindView on fields.

                      Group multiple views in a list or array. Operate on all of them at once with actions, setters, or properties.

                      Eliminate anonymous inner-classes for listeners by annotating methods with @OnClick and others.

                      Eliminate resource lookups by using resource annotations on fields.

                      default

                      copy iconCopydownload iconDownload
                      class ExampleActivity extends Activity {
                        @BindView(R.id.user) EditText username;
                        @BindView(R.id.pass) EditText password;
                      
                        @BindString(R.string.login_error) String loginErrorMessage;
                      
                        @OnClick(R.id.submit) void submit() {
                          // TODO call server...
                        }
                      
                        @Override public void onCreate(Bundle savedInstanceState) {
                          super.onCreate(savedInstanceState);
                          setContentView(R.layout.simple_activity);
                          ButterKnife.bind(this);
                          // TODO Use fields...
                        }
                      }

                      Download

                      copy iconCopydownload iconDownload
                      android {
                        ...
                        // Butterknife requires Java 8.
                        compileOptions {
                          sourceCompatibility JavaVersion.VERSION_1_8
                          targetCompatibility JavaVersion.VERSION_1_8
                        }
                      }
                      
                      dependencies {
                        implementation 'com.jakewharton:butterknife:10.2.3'
                        annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'
                      }

                      Gradle Failure A problem occurred evaluating project ':app' after update android Studio

                      copy iconCopydownload iconDownload
                      buildToolsVersion '30.0.2'
                      
                      buildToolsVersion "30.0.2"
                      
                      maven {
                              url 'https://maven.google.com/'
                              name 'Google'
                          }
                      
                      targetSdkVersion 27
                      minSdk 21
                      
                      buildToolsVersion '30.0.2'
                      
                      buildToolsVersion "30.0.2"
                      
                      maven {
                              url 'https://maven.google.com/'
                              name 'Google'
                          }
                      
                      targetSdkVersion 27
                      minSdk 21
                      
                      buildToolsVersion '30.0.2'
                      
                      buildToolsVersion "30.0.2"
                      
                      maven {
                              url 'https://maven.google.com/'
                              name 'Google'
                          }
                      
                      targetSdkVersion 27
                      minSdk 21
                      
                      buildToolsVersion '30.0.2'
                      
                      buildToolsVersion "30.0.2"
                      
                      maven {
                              url 'https://maven.google.com/'
                              name 'Google'
                          }
                      
                      targetSdkVersion 27
                      minSdk 21
                      

                      PopupWindow .showAsDropDown() unable to shift left or right (But up and down both work)

                      copy iconCopydownload iconDownload
                      int[] anchorView = new int[2];
                      anchorButton.getLocationInWindow(anchorView); // anchor button location in the window
                      popupWindow.showAtLocation(getWindow().getDecorView(), Gravity.NO_GRAVITY,
                              anchorView[0] + 50,
                              anchorView[1] + anchorButton.getHeight() -30);
                      
                      <?xml version="1.0" encoding="utf-8"?>
                      <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
                          xmlns:app="http://schemas.android.com/apk/res-auto"
                          android:layout_width="match_parent"
                          android:layout_height="match_parent">
                      
                          <TextView
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                              android:text="test clear"
                              app:layout_constraintBottom_toBottomOf="parent"
                              app:layout_constraintEnd_toEndOf="parent"
                              app:layout_constraintStart_toStartOf="parent"
                              app:layout_constraintTop_toTopOf="parent" />
                      
                      </androidx.constraintlayout.widget.ConstraintLayout>
                      
                      Button button = findViewById(R.id.button);
                      PopupWindow popupWindow = new TestWindow(MainActivity.this);
                      popupWindow.showAsDropDown(button, 50, -30);
                      
                      int[] anchorView = new int[2];
                      anchorButton.getLocationInWindow(anchorView); // anchor button location in the window
                      popupWindow.showAtLocation(getWindow().getDecorView(), Gravity.NO_GRAVITY,
                              anchorView[0] + 50,
                              anchorView[1] + anchorButton.getHeight() -30);
                      
                      <?xml version="1.0" encoding="utf-8"?>
                      <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
                          xmlns:app="http://schemas.android.com/apk/res-auto"
                          android:layout_width="match_parent"
                          android:layout_height="match_parent">
                      
                          <TextView
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                              android:text="test clear"
                              app:layout_constraintBottom_toBottomOf="parent"
                              app:layout_constraintEnd_toEndOf="parent"
                              app:layout_constraintStart_toStartOf="parent"
                              app:layout_constraintTop_toTopOf="parent" />
                      
                      </androidx.constraintlayout.widget.ConstraintLayout>
                      
                      Button button = findViewById(R.id.button);
                      PopupWindow popupWindow = new TestWindow(MainActivity.this);
                      popupWindow.showAsDropDown(button, 50, -30);
                      
                      int[] anchorView = new int[2];
                      anchorButton.getLocationInWindow(anchorView); // anchor button location in the window
                      popupWindow.showAtLocation(getWindow().getDecorView(), Gravity.NO_GRAVITY,
                              anchorView[0] + 50,
                              anchorView[1] + anchorButton.getHeight() -30);
                      
                      <?xml version="1.0" encoding="utf-8"?>
                      <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
                          xmlns:app="http://schemas.android.com/apk/res-auto"
                          android:layout_width="match_parent"
                          android:layout_height="match_parent">
                      
                          <TextView
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                              android:text="test clear"
                              app:layout_constraintBottom_toBottomOf="parent"
                              app:layout_constraintEnd_toEndOf="parent"
                              app:layout_constraintStart_toStartOf="parent"
                              app:layout_constraintTop_toTopOf="parent" />
                      
                      </androidx.constraintlayout.widget.ConstraintLayout>
                      
                      Button button = findViewById(R.id.button);
                      PopupWindow popupWindow = new TestWindow(MainActivity.this);
                      popupWindow.showAsDropDown(button, 50, -30);
                      

                      Which lifecycle method should I place my network call so it doesn't get called again when the screen rotates?

                      copy iconCopydownload iconDownload
                      init {
                      getPosts()
                      }
                      

                      Can not run the the tflite model on Interpreter in android studio

                      copy iconCopydownload iconDownload
                      implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT'
                      
                      protected MappedByteBuffer loadMappedFile(String filePath) throws IOException {
                          AssetFileDescriptor fileDescriptor = assetManager.openFd(this.directoryName + "/" + filePath);
                      
                          FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
                          FileChannel fileChannel = inputStream.getChannel();
                          long startOffset = fileDescriptor.getStartOffset();
                          long declaredLength = fileDescriptor.getDeclaredLength();
                          return fileChannel.map(MapMode.READ_ONLY, startOffset, declaredLength);
                        }
                      
                      implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT'
                      
                      protected MappedByteBuffer loadMappedFile(String filePath) throws IOException {
                          AssetFileDescriptor fileDescriptor = assetManager.openFd(this.directoryName + "/" + filePath);
                      
                          FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
                          FileChannel fileChannel = inputStream.getChannel();
                          long startOffset = fileDescriptor.getStartOffset();
                          long declaredLength = fileDescriptor.getDeclaredLength();
                          return fileChannel.map(MapMode.READ_ONLY, startOffset, declaredLength);
                        }
                      

                      How to fix gradle which stopped working - error while syncing?

                      copy iconCopydownload iconDownload
                      // Gradle
                      implementation com.android.tools.build:gradle);
                      
                      // Gradle
                      implementation 'com.android.tools.build:gradle'
                      
                      // Gradle
                      implementation com.android.tools.build:gradle);
                      
                      // Gradle
                      implementation 'com.android.tools.build:gradle'
                      

                      Duplicate class in build.gradle file

                      copy iconCopydownload iconDownload
                      testImplementation 'junit:junit:4.+'
                      testImplementation 'junit:junit:4.12'
                      
                      configurations.all {
                          resolutionStrategy.dependencySubstitution {
                              substitute module('org.hamcrest:hamcrest-core:1.1') with module('junit:junit:4.10')
                          }
                      }
                      

                      What is this Error when Debug android app?

                      copy iconCopydownload iconDownload
                      private ActivityResultLauncher requestPermissionLauncher =
                                  registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> { {
                                          //result is a map(string permission,boolean granted or not)
                                          //to check if all permissions were granted or not
                                          if(result.containsValue(false)){ 
                                          // Explain to the user that the feature is unavailable because
                                          // the features requires a permission that the user has denied.
                                          // At the same time, respect the user's decision. Don't link to
                                          // system settings in an effort to convince the user to change
                                          // their decision.
                                          Toast.makeText(getContext(), "Can't continue without the required permissions", Toast.LENGTH_LONG).show();
                                          }
                                          else { 
                                             //continue your work flow
                                          }
                                              
                                      });
                      
                                  if (ActivityCompat.checkSelfPermission(getContext(),
                                          Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED ||  
                                          ActivityCompat.checkSelfPermission(getContext(),
                                          Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED ||   
                                          ActivityCompat.checkSelfPermission(getContext(),
                                          Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.ACCESS_FINE_LOCATION) {
                      
                                          requestPermissionLauncher.launch(new String[]{Manifest.permission.CALL_PHONE,
                                          Manifest.permission.ACCESS_COARSE_LOCATION,
                                          Manifest.permission.ACCESS_FINE_LOCATION});
                      
                                  } else // continue your work
                      
                      private ActivityResultLauncher requestPermissionLauncher =
                                  registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> { {
                                          //result is a map(string permission,boolean granted or not)
                                          //to check if all permissions were granted or not
                                          if(result.containsValue(false)){ 
                                          // Explain to the user that the feature is unavailable because
                                          // the features requires a permission that the user has denied.
                                          // At the same time, respect the user's decision. Don't link to
                                          // system settings in an effort to convince the user to change
                                          // their decision.
                                          Toast.makeText(getContext(), "Can't continue without the required permissions", Toast.LENGTH_LONG).show();
                                          }
                                          else { 
                                             //continue your work flow
                                          }
                                              
                                      });
                      
                                  if (ActivityCompat.checkSelfPermission(getContext(),
                                          Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED ||  
                                          ActivityCompat.checkSelfPermission(getContext(),
                                          Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED ||   
                                          ActivityCompat.checkSelfPermission(getContext(),
                                          Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.ACCESS_FINE_LOCATION) {
                      
                                          requestPermissionLauncher.launch(new String[]{Manifest.permission.CALL_PHONE,
                                          Manifest.permission.ACCESS_COARSE_LOCATION,
                                          Manifest.permission.ACCESS_FINE_LOCATION});
                      
                                  } else // continue your work
                      
                       if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                           requestPermissions(INITIAL_PERMS, INITIAL_REQUEST);
                       }
                      

                      Library to change to fix Google app publish error; Billing Library version 3 in android studio

                      copy iconCopydownload iconDownload
                      implementation 'com.anjlab.android.iab.v3:library:1.1.0'
                      
                      implementation 'com.android.billingclient:billing:4.0.0'
                      
                      <string name="license_key">Place Your ID Here</string>
                      <string name="product_id">android.test.purchased</string>
                      
                      import android.app.Activity
                      import android.content.Context
                      import android.widget.Toast
                      import com.android.billingclient.api.*
                      import java.io.IOException
                      import java.util.ArrayList
                      
                      class InAppPurchase(context: Context) : PurchasesUpdatedListener{
                          private val mContext: Context = context
                          private var billingClient: BillingClient
                          var ackPurchase =
                              AcknowledgePurchaseResponseListener { billingResult ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      //if purchase is acknowledged
                                      // Grant entitlement to the user. and restart activity
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext, true)
                                      showMessage("Item Purchased")
                                      (mContext as Activity).recreate()
                                  }
                              }
                      
                          init {
                              billingClient =
                                  BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                              billingClient.startConnection(object : BillingClientStateListener {
                                  override fun onBillingSetupFinished(billingResult: BillingResult) {
                                      if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                          val queryPurchase = billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                          val queryPurchases = queryPurchase.purchasesList
                                          if (queryPurchases != null && queryPurchases.size > 0) {
                                              handlePurchases(queryPurchases)
                                          } else {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext, false)
                                          }
                                      }
                                  }
                      
                                  override fun onBillingServiceDisconnected() {}
                              })
                          }
                      
                          fun productPurchase() {
                              //check if service is already connected
                              if (billingClient.isReady) {
                                  initiatePurchase()
                              } else {
                                  billingClient =
                                      BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                                  billingClient.startConnection(object : BillingClientStateListener {
                                      override fun onBillingSetupFinished(billingResult: BillingResult) {
                                          if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                              initiatePurchase()
                                          } else {
                                              showMessage("Error" + billingResult.debugMessage)
                                          }
                                      }
                      
                                      override fun onBillingServiceDisconnected() {}
                                  })
                              }
                          }
                      
                          private fun initiatePurchase() {
                              val skuList: MutableList<String> = ArrayList()
                              skuList.add(mContext.resources.getString(R.string.product_id))
                              val params = SkuDetailsParams.newBuilder()
                              params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
                              billingClient.querySkuDetailsAsync(
                                  params.build()
                              ) { billingResult, skuDetailsList ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      if (skuDetailsList != null && skuDetailsList.size > 0) {
                                          val flowParams = BillingFlowParams.newBuilder()
                                              .setSkuDetails(skuDetailsList[0])
                                              .build()
                                          billingClient.launchBillingFlow(mContext as Activity, flowParams)
                                      } else {
                                          //try to add item/product id "purchase" inside managed product in google play console
                                          showMessage("Purchase Item not Found")
                                      }
                                  } else {
                                      showMessage(" Error " + billingResult.debugMessage)
                                  }
                              }
                          }
                      
                          /**
                           * Verifies that the purchase was signed correctly for this developer's public key.
                           *
                           * Note: It's strongly recommended to perform such check on your backend since hackers can
                           * replace this method with "constant true" if they decompile/rebuild your app.
                           *
                           */
                          private fun verifyValidSignature(signedData: String, signature: String): Boolean {
                              return try {
                                  // To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
                                  val base64Key = mContext.getString(R.string.license_key)
                                  Security.verifyPurchase(base64Key, signedData, signature)
                              } catch (e: IOException) {
                                  false
                              }
                          }
                      
                          fun handlePurchases(purchases: List<Purchase>) {
                              for (purchase in purchases) {
                                  //if item is purchased
                                  if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                                      if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
                                          // Invalid purchase
                                          // show error to user
                                         showMessage("Invalid Purchase")
                                          return
                                      }
                      //                 else purchase is valid
                      //                if item is purchased and not acknowledged
                                      if (!purchase.isAcknowledged) {
                                          val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                                              .setPurchaseToken(purchase.purchaseToken)
                                              .build()
                                          billingClient.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
                                      } else {
                                          // Grant entitlement to the user on item purchase
                                          // restart activity
                                          if (!SharedPreferencesUtils.getPurchasedBillingValue(mContext)) {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext,true)
                                              showMessage("Item Purchased")
                                              (mContext as Activity).recreate()
                                          }
                                      }
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
                                      showMessage("Purchase is Pending. Please complete Transaction")
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext,false)
                                      showMessage("Purchase Status Unknown")
                                  }
                              }
                      
                      
                          }
                      
                      
                          private fun showMessage(message: String) {
                              (mContext as Activity).runOnUiThread{
                                  Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
                              }
                      
                          }
                      
                          override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
                              //if item newly purchased
                              if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
                                  handlePurchases(purchases)
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
                                  val queryAlreadyPurchasesResult =
                                      billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                  val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
                                  alreadyPurchases?.let { handlePurchases(it) }
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
                                  showMessage("Purchase Canceled")
                              } else {
                                  showMessage("Error updated" + billingResult.debugMessage)
                              }
                          }
                      
                      
                          fun onDestroyBilling() {
                              billingClient.endConnection()
                          }
                      
                      }
                      
                      import android.text.TextUtils
                      import android.util.Base64
                      import java.io.IOException
                      import java.security.*
                      import java.security.spec.InvalidKeySpecException
                      import java.security.spec.X509EncodedKeySpec
                      
                      /**
                       * Security-related methods. For a secure implementation, all of this code should be implemented on
                       * a server that communicates with the application on the device.
                       */
                      object Security {
                      
                          private const val KEY_FACTORY_ALGORITHM = "RSA"
                          private const val SIGNATURE_ALGORITHM = "SHA1withRSA"
                      
                          /**
                           * Verifies that the data was signed with the given signature, and returns the verified
                           * purchase.
                           * @param base64PublicKey the base64-encoded public key to use for verifying.
                           * @param signedData the signed JSON string (signed, not encrypted)
                           * @param signature the signature for the data, signed with the private key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun verifyPurchase(
                              base64PublicKey: String, signedData: String,
                              signature: String
                          ): Boolean {
                              if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
                                  || TextUtils.isEmpty(signature)
                              ) {
                                  //Purchase verification failed: missing data
                                  return false
                              }
                              val key = generatePublicKey(base64PublicKey)
                              return verify(key, signedData, signature)
                          }
                      
                          /**
                           * Generates a PublicKey instance from a string containing the Base64-encoded public key.
                           *
                           * @param encodedPublicKey Base64-encoded public key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun generatePublicKey(encodedPublicKey: String): PublicKey {
                              return try {
                                  val decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT)
                                  val keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
                                  keyFactory.generatePublic(X509EncodedKeySpec(decodedKey))
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available.
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeySpecException) {
                                  val msg = "Invalid key specification: $e"
                                  throw IOException(msg)
                              }
                          }
                      
                          /**
                           * Verifies that the signature from the server matches the computed signature on the data.
                           * Returns true if the data is correctly signed.
                           *
                           * @param publicKey public key associated with the developer account
                           * @param signedData signed data from server
                           * @param signature server signature
                           * @return true if the data and signature match
                           */
                          private fun verify(publicKey: PublicKey, signedData: String, signature: String): Boolean {
                              val signatureBytes: ByteArray = try {
                                  Base64.decode(signature, Base64.DEFAULT)
                              } catch (e: IllegalArgumentException) {
                                  //Base64 decoding failed
                                  return false
                              }
                              try {
                                  val signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM)
                                  signatureAlgorithm.initVerify(publicKey)
                                  signatureAlgorithm.update(signedData.toByteArray())
                                  return signatureAlgorithm.verify(signatureBytes)
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeyException) {
                                  //Invalid key specification
                              } catch (e: SignatureException) {
                                  //Signature exception
                              }
                              return false
                          }
                      
                      }
                      
                      var inAppPurchase: InAppPurchase  = InAppPurchase(this)
                      btnInApp.setOnClickListener {
                                  inAppPurchase.productPurchase()
                              }
                      
                      implementation 'com.anjlab.android.iab.v3:library:1.1.0'
                      
                      implementation 'com.android.billingclient:billing:4.0.0'
                      
                      <string name="license_key">Place Your ID Here</string>
                      <string name="product_id">android.test.purchased</string>
                      
                      import android.app.Activity
                      import android.content.Context
                      import android.widget.Toast
                      import com.android.billingclient.api.*
                      import java.io.IOException
                      import java.util.ArrayList
                      
                      class InAppPurchase(context: Context) : PurchasesUpdatedListener{
                          private val mContext: Context = context
                          private var billingClient: BillingClient
                          var ackPurchase =
                              AcknowledgePurchaseResponseListener { billingResult ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      //if purchase is acknowledged
                                      // Grant entitlement to the user. and restart activity
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext, true)
                                      showMessage("Item Purchased")
                                      (mContext as Activity).recreate()
                                  }
                              }
                      
                          init {
                              billingClient =
                                  BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                              billingClient.startConnection(object : BillingClientStateListener {
                                  override fun onBillingSetupFinished(billingResult: BillingResult) {
                                      if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                          val queryPurchase = billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                          val queryPurchases = queryPurchase.purchasesList
                                          if (queryPurchases != null && queryPurchases.size > 0) {
                                              handlePurchases(queryPurchases)
                                          } else {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext, false)
                                          }
                                      }
                                  }
                      
                                  override fun onBillingServiceDisconnected() {}
                              })
                          }
                      
                          fun productPurchase() {
                              //check if service is already connected
                              if (billingClient.isReady) {
                                  initiatePurchase()
                              } else {
                                  billingClient =
                                      BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                                  billingClient.startConnection(object : BillingClientStateListener {
                                      override fun onBillingSetupFinished(billingResult: BillingResult) {
                                          if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                              initiatePurchase()
                                          } else {
                                              showMessage("Error" + billingResult.debugMessage)
                                          }
                                      }
                      
                                      override fun onBillingServiceDisconnected() {}
                                  })
                              }
                          }
                      
                          private fun initiatePurchase() {
                              val skuList: MutableList<String> = ArrayList()
                              skuList.add(mContext.resources.getString(R.string.product_id))
                              val params = SkuDetailsParams.newBuilder()
                              params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
                              billingClient.querySkuDetailsAsync(
                                  params.build()
                              ) { billingResult, skuDetailsList ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      if (skuDetailsList != null && skuDetailsList.size > 0) {
                                          val flowParams = BillingFlowParams.newBuilder()
                                              .setSkuDetails(skuDetailsList[0])
                                              .build()
                                          billingClient.launchBillingFlow(mContext as Activity, flowParams)
                                      } else {
                                          //try to add item/product id "purchase" inside managed product in google play console
                                          showMessage("Purchase Item not Found")
                                      }
                                  } else {
                                      showMessage(" Error " + billingResult.debugMessage)
                                  }
                              }
                          }
                      
                          /**
                           * Verifies that the purchase was signed correctly for this developer's public key.
                           *
                           * Note: It's strongly recommended to perform such check on your backend since hackers can
                           * replace this method with "constant true" if they decompile/rebuild your app.
                           *
                           */
                          private fun verifyValidSignature(signedData: String, signature: String): Boolean {
                              return try {
                                  // To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
                                  val base64Key = mContext.getString(R.string.license_key)
                                  Security.verifyPurchase(base64Key, signedData, signature)
                              } catch (e: IOException) {
                                  false
                              }
                          }
                      
                          fun handlePurchases(purchases: List<Purchase>) {
                              for (purchase in purchases) {
                                  //if item is purchased
                                  if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                                      if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
                                          // Invalid purchase
                                          // show error to user
                                         showMessage("Invalid Purchase")
                                          return
                                      }
                      //                 else purchase is valid
                      //                if item is purchased and not acknowledged
                                      if (!purchase.isAcknowledged) {
                                          val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                                              .setPurchaseToken(purchase.purchaseToken)
                                              .build()
                                          billingClient.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
                                      } else {
                                          // Grant entitlement to the user on item purchase
                                          // restart activity
                                          if (!SharedPreferencesUtils.getPurchasedBillingValue(mContext)) {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext,true)
                                              showMessage("Item Purchased")
                                              (mContext as Activity).recreate()
                                          }
                                      }
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
                                      showMessage("Purchase is Pending. Please complete Transaction")
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext,false)
                                      showMessage("Purchase Status Unknown")
                                  }
                              }
                      
                      
                          }
                      
                      
                          private fun showMessage(message: String) {
                              (mContext as Activity).runOnUiThread{
                                  Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
                              }
                      
                          }
                      
                          override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
                              //if item newly purchased
                              if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
                                  handlePurchases(purchases)
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
                                  val queryAlreadyPurchasesResult =
                                      billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                  val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
                                  alreadyPurchases?.let { handlePurchases(it) }
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
                                  showMessage("Purchase Canceled")
                              } else {
                                  showMessage("Error updated" + billingResult.debugMessage)
                              }
                          }
                      
                      
                          fun onDestroyBilling() {
                              billingClient.endConnection()
                          }
                      
                      }
                      
                      import android.text.TextUtils
                      import android.util.Base64
                      import java.io.IOException
                      import java.security.*
                      import java.security.spec.InvalidKeySpecException
                      import java.security.spec.X509EncodedKeySpec
                      
                      /**
                       * Security-related methods. For a secure implementation, all of this code should be implemented on
                       * a server that communicates with the application on the device.
                       */
                      object Security {
                      
                          private const val KEY_FACTORY_ALGORITHM = "RSA"
                          private const val SIGNATURE_ALGORITHM = "SHA1withRSA"
                      
                          /**
                           * Verifies that the data was signed with the given signature, and returns the verified
                           * purchase.
                           * @param base64PublicKey the base64-encoded public key to use for verifying.
                           * @param signedData the signed JSON string (signed, not encrypted)
                           * @param signature the signature for the data, signed with the private key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun verifyPurchase(
                              base64PublicKey: String, signedData: String,
                              signature: String
                          ): Boolean {
                              if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
                                  || TextUtils.isEmpty(signature)
                              ) {
                                  //Purchase verification failed: missing data
                                  return false
                              }
                              val key = generatePublicKey(base64PublicKey)
                              return verify(key, signedData, signature)
                          }
                      
                          /**
                           * Generates a PublicKey instance from a string containing the Base64-encoded public key.
                           *
                           * @param encodedPublicKey Base64-encoded public key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun generatePublicKey(encodedPublicKey: String): PublicKey {
                              return try {
                                  val decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT)
                                  val keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
                                  keyFactory.generatePublic(X509EncodedKeySpec(decodedKey))
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available.
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeySpecException) {
                                  val msg = "Invalid key specification: $e"
                                  throw IOException(msg)
                              }
                          }
                      
                          /**
                           * Verifies that the signature from the server matches the computed signature on the data.
                           * Returns true if the data is correctly signed.
                           *
                           * @param publicKey public key associated with the developer account
                           * @param signedData signed data from server
                           * @param signature server signature
                           * @return true if the data and signature match
                           */
                          private fun verify(publicKey: PublicKey, signedData: String, signature: String): Boolean {
                              val signatureBytes: ByteArray = try {
                                  Base64.decode(signature, Base64.DEFAULT)
                              } catch (e: IllegalArgumentException) {
                                  //Base64 decoding failed
                                  return false
                              }
                              try {
                                  val signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM)
                                  signatureAlgorithm.initVerify(publicKey)
                                  signatureAlgorithm.update(signedData.toByteArray())
                                  return signatureAlgorithm.verify(signatureBytes)
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeyException) {
                                  //Invalid key specification
                              } catch (e: SignatureException) {
                                  //Signature exception
                              }
                              return false
                          }
                      
                      }
                      
                      var inAppPurchase: InAppPurchase  = InAppPurchase(this)
                      btnInApp.setOnClickListener {
                                  inAppPurchase.productPurchase()
                              }
                      
                      implementation 'com.anjlab.android.iab.v3:library:1.1.0'
                      
                      implementation 'com.android.billingclient:billing:4.0.0'
                      
                      <string name="license_key">Place Your ID Here</string>
                      <string name="product_id">android.test.purchased</string>
                      
                      import android.app.Activity
                      import android.content.Context
                      import android.widget.Toast
                      import com.android.billingclient.api.*
                      import java.io.IOException
                      import java.util.ArrayList
                      
                      class InAppPurchase(context: Context) : PurchasesUpdatedListener{
                          private val mContext: Context = context
                          private var billingClient: BillingClient
                          var ackPurchase =
                              AcknowledgePurchaseResponseListener { billingResult ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      //if purchase is acknowledged
                                      // Grant entitlement to the user. and restart activity
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext, true)
                                      showMessage("Item Purchased")
                                      (mContext as Activity).recreate()
                                  }
                              }
                      
                          init {
                              billingClient =
                                  BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                              billingClient.startConnection(object : BillingClientStateListener {
                                  override fun onBillingSetupFinished(billingResult: BillingResult) {
                                      if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                          val queryPurchase = billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                          val queryPurchases = queryPurchase.purchasesList
                                          if (queryPurchases != null && queryPurchases.size > 0) {
                                              handlePurchases(queryPurchases)
                                          } else {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext, false)
                                          }
                                      }
                                  }
                      
                                  override fun onBillingServiceDisconnected() {}
                              })
                          }
                      
                          fun productPurchase() {
                              //check if service is already connected
                              if (billingClient.isReady) {
                                  initiatePurchase()
                              } else {
                                  billingClient =
                                      BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                                  billingClient.startConnection(object : BillingClientStateListener {
                                      override fun onBillingSetupFinished(billingResult: BillingResult) {
                                          if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                              initiatePurchase()
                                          } else {
                                              showMessage("Error" + billingResult.debugMessage)
                                          }
                                      }
                      
                                      override fun onBillingServiceDisconnected() {}
                                  })
                              }
                          }
                      
                          private fun initiatePurchase() {
                              val skuList: MutableList<String> = ArrayList()
                              skuList.add(mContext.resources.getString(R.string.product_id))
                              val params = SkuDetailsParams.newBuilder()
                              params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
                              billingClient.querySkuDetailsAsync(
                                  params.build()
                              ) { billingResult, skuDetailsList ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      if (skuDetailsList != null && skuDetailsList.size > 0) {
                                          val flowParams = BillingFlowParams.newBuilder()
                                              .setSkuDetails(skuDetailsList[0])
                                              .build()
                                          billingClient.launchBillingFlow(mContext as Activity, flowParams)
                                      } else {
                                          //try to add item/product id "purchase" inside managed product in google play console
                                          showMessage("Purchase Item not Found")
                                      }
                                  } else {
                                      showMessage(" Error " + billingResult.debugMessage)
                                  }
                              }
                          }
                      
                          /**
                           * Verifies that the purchase was signed correctly for this developer's public key.
                           *
                           * Note: It's strongly recommended to perform such check on your backend since hackers can
                           * replace this method with "constant true" if they decompile/rebuild your app.
                           *
                           */
                          private fun verifyValidSignature(signedData: String, signature: String): Boolean {
                              return try {
                                  // To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
                                  val base64Key = mContext.getString(R.string.license_key)
                                  Security.verifyPurchase(base64Key, signedData, signature)
                              } catch (e: IOException) {
                                  false
                              }
                          }
                      
                          fun handlePurchases(purchases: List<Purchase>) {
                              for (purchase in purchases) {
                                  //if item is purchased
                                  if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                                      if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
                                          // Invalid purchase
                                          // show error to user
                                         showMessage("Invalid Purchase")
                                          return
                                      }
                      //                 else purchase is valid
                      //                if item is purchased and not acknowledged
                                      if (!purchase.isAcknowledged) {
                                          val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                                              .setPurchaseToken(purchase.purchaseToken)
                                              .build()
                                          billingClient.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
                                      } else {
                                          // Grant entitlement to the user on item purchase
                                          // restart activity
                                          if (!SharedPreferencesUtils.getPurchasedBillingValue(mContext)) {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext,true)
                                              showMessage("Item Purchased")
                                              (mContext as Activity).recreate()
                                          }
                                      }
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
                                      showMessage("Purchase is Pending. Please complete Transaction")
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext,false)
                                      showMessage("Purchase Status Unknown")
                                  }
                              }
                      
                      
                          }
                      
                      
                          private fun showMessage(message: String) {
                              (mContext as Activity).runOnUiThread{
                                  Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
                              }
                      
                          }
                      
                          override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
                              //if item newly purchased
                              if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
                                  handlePurchases(purchases)
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
                                  val queryAlreadyPurchasesResult =
                                      billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                  val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
                                  alreadyPurchases?.let { handlePurchases(it) }
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
                                  showMessage("Purchase Canceled")
                              } else {
                                  showMessage("Error updated" + billingResult.debugMessage)
                              }
                          }
                      
                      
                          fun onDestroyBilling() {
                              billingClient.endConnection()
                          }
                      
                      }
                      
                      import android.text.TextUtils
                      import android.util.Base64
                      import java.io.IOException
                      import java.security.*
                      import java.security.spec.InvalidKeySpecException
                      import java.security.spec.X509EncodedKeySpec
                      
                      /**
                       * Security-related methods. For a secure implementation, all of this code should be implemented on
                       * a server that communicates with the application on the device.
                       */
                      object Security {
                      
                          private const val KEY_FACTORY_ALGORITHM = "RSA"
                          private const val SIGNATURE_ALGORITHM = "SHA1withRSA"
                      
                          /**
                           * Verifies that the data was signed with the given signature, and returns the verified
                           * purchase.
                           * @param base64PublicKey the base64-encoded public key to use for verifying.
                           * @param signedData the signed JSON string (signed, not encrypted)
                           * @param signature the signature for the data, signed with the private key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun verifyPurchase(
                              base64PublicKey: String, signedData: String,
                              signature: String
                          ): Boolean {
                              if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
                                  || TextUtils.isEmpty(signature)
                              ) {
                                  //Purchase verification failed: missing data
                                  return false
                              }
                              val key = generatePublicKey(base64PublicKey)
                              return verify(key, signedData, signature)
                          }
                      
                          /**
                           * Generates a PublicKey instance from a string containing the Base64-encoded public key.
                           *
                           * @param encodedPublicKey Base64-encoded public key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun generatePublicKey(encodedPublicKey: String): PublicKey {
                              return try {
                                  val decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT)
                                  val keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
                                  keyFactory.generatePublic(X509EncodedKeySpec(decodedKey))
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available.
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeySpecException) {
                                  val msg = "Invalid key specification: $e"
                                  throw IOException(msg)
                              }
                          }
                      
                          /**
                           * Verifies that the signature from the server matches the computed signature on the data.
                           * Returns true if the data is correctly signed.
                           *
                           * @param publicKey public key associated with the developer account
                           * @param signedData signed data from server
                           * @param signature server signature
                           * @return true if the data and signature match
                           */
                          private fun verify(publicKey: PublicKey, signedData: String, signature: String): Boolean {
                              val signatureBytes: ByteArray = try {
                                  Base64.decode(signature, Base64.DEFAULT)
                              } catch (e: IllegalArgumentException) {
                                  //Base64 decoding failed
                                  return false
                              }
                              try {
                                  val signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM)
                                  signatureAlgorithm.initVerify(publicKey)
                                  signatureAlgorithm.update(signedData.toByteArray())
                                  return signatureAlgorithm.verify(signatureBytes)
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeyException) {
                                  //Invalid key specification
                              } catch (e: SignatureException) {
                                  //Signature exception
                              }
                              return false
                          }
                      
                      }
                      
                      var inAppPurchase: InAppPurchase  = InAppPurchase(this)
                      btnInApp.setOnClickListener {
                                  inAppPurchase.productPurchase()
                              }
                      
                      implementation 'com.anjlab.android.iab.v3:library:1.1.0'
                      
                      implementation 'com.android.billingclient:billing:4.0.0'
                      
                      <string name="license_key">Place Your ID Here</string>
                      <string name="product_id">android.test.purchased</string>
                      
                      import android.app.Activity
                      import android.content.Context
                      import android.widget.Toast
                      import com.android.billingclient.api.*
                      import java.io.IOException
                      import java.util.ArrayList
                      
                      class InAppPurchase(context: Context) : PurchasesUpdatedListener{
                          private val mContext: Context = context
                          private var billingClient: BillingClient
                          var ackPurchase =
                              AcknowledgePurchaseResponseListener { billingResult ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      //if purchase is acknowledged
                                      // Grant entitlement to the user. and restart activity
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext, true)
                                      showMessage("Item Purchased")
                                      (mContext as Activity).recreate()
                                  }
                              }
                      
                          init {
                              billingClient =
                                  BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                              billingClient.startConnection(object : BillingClientStateListener {
                                  override fun onBillingSetupFinished(billingResult: BillingResult) {
                                      if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                          val queryPurchase = billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                          val queryPurchases = queryPurchase.purchasesList
                                          if (queryPurchases != null && queryPurchases.size > 0) {
                                              handlePurchases(queryPurchases)
                                          } else {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext, false)
                                          }
                                      }
                                  }
                      
                                  override fun onBillingServiceDisconnected() {}
                              })
                          }
                      
                          fun productPurchase() {
                              //check if service is already connected
                              if (billingClient.isReady) {
                                  initiatePurchase()
                              } else {
                                  billingClient =
                                      BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                                  billingClient.startConnection(object : BillingClientStateListener {
                                      override fun onBillingSetupFinished(billingResult: BillingResult) {
                                          if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                              initiatePurchase()
                                          } else {
                                              showMessage("Error" + billingResult.debugMessage)
                                          }
                                      }
                      
                                      override fun onBillingServiceDisconnected() {}
                                  })
                              }
                          }
                      
                          private fun initiatePurchase() {
                              val skuList: MutableList<String> = ArrayList()
                              skuList.add(mContext.resources.getString(R.string.product_id))
                              val params = SkuDetailsParams.newBuilder()
                              params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
                              billingClient.querySkuDetailsAsync(
                                  params.build()
                              ) { billingResult, skuDetailsList ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      if (skuDetailsList != null && skuDetailsList.size > 0) {
                                          val flowParams = BillingFlowParams.newBuilder()
                                              .setSkuDetails(skuDetailsList[0])
                                              .build()
                                          billingClient.launchBillingFlow(mContext as Activity, flowParams)
                                      } else {
                                          //try to add item/product id "purchase" inside managed product in google play console
                                          showMessage("Purchase Item not Found")
                                      }
                                  } else {
                                      showMessage(" Error " + billingResult.debugMessage)
                                  }
                              }
                          }
                      
                          /**
                           * Verifies that the purchase was signed correctly for this developer's public key.
                           *
                           * Note: It's strongly recommended to perform such check on your backend since hackers can
                           * replace this method with "constant true" if they decompile/rebuild your app.
                           *
                           */
                          private fun verifyValidSignature(signedData: String, signature: String): Boolean {
                              return try {
                                  // To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
                                  val base64Key = mContext.getString(R.string.license_key)
                                  Security.verifyPurchase(base64Key, signedData, signature)
                              } catch (e: IOException) {
                                  false
                              }
                          }
                      
                          fun handlePurchases(purchases: List<Purchase>) {
                              for (purchase in purchases) {
                                  //if item is purchased
                                  if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                                      if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
                                          // Invalid purchase
                                          // show error to user
                                         showMessage("Invalid Purchase")
                                          return
                                      }
                      //                 else purchase is valid
                      //                if item is purchased and not acknowledged
                                      if (!purchase.isAcknowledged) {
                                          val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                                              .setPurchaseToken(purchase.purchaseToken)
                                              .build()
                                          billingClient.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
                                      } else {
                                          // Grant entitlement to the user on item purchase
                                          // restart activity
                                          if (!SharedPreferencesUtils.getPurchasedBillingValue(mContext)) {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext,true)
                                              showMessage("Item Purchased")
                                              (mContext as Activity).recreate()
                                          }
                                      }
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
                                      showMessage("Purchase is Pending. Please complete Transaction")
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext,false)
                                      showMessage("Purchase Status Unknown")
                                  }
                              }
                      
                      
                          }
                      
                      
                          private fun showMessage(message: String) {
                              (mContext as Activity).runOnUiThread{
                                  Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
                              }
                      
                          }
                      
                          override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
                              //if item newly purchased
                              if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
                                  handlePurchases(purchases)
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
                                  val queryAlreadyPurchasesResult =
                                      billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                  val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
                                  alreadyPurchases?.let { handlePurchases(it) }
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
                                  showMessage("Purchase Canceled")
                              } else {
                                  showMessage("Error updated" + billingResult.debugMessage)
                              }
                          }
                      
                      
                          fun onDestroyBilling() {
                              billingClient.endConnection()
                          }
                      
                      }
                      
                      import android.text.TextUtils
                      import android.util.Base64
                      import java.io.IOException
                      import java.security.*
                      import java.security.spec.InvalidKeySpecException
                      import java.security.spec.X509EncodedKeySpec
                      
                      /**
                       * Security-related methods. For a secure implementation, all of this code should be implemented on
                       * a server that communicates with the application on the device.
                       */
                      object Security {
                      
                          private const val KEY_FACTORY_ALGORITHM = "RSA"
                          private const val SIGNATURE_ALGORITHM = "SHA1withRSA"
                      
                          /**
                           * Verifies that the data was signed with the given signature, and returns the verified
                           * purchase.
                           * @param base64PublicKey the base64-encoded public key to use for verifying.
                           * @param signedData the signed JSON string (signed, not encrypted)
                           * @param signature the signature for the data, signed with the private key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun verifyPurchase(
                              base64PublicKey: String, signedData: String,
                              signature: String
                          ): Boolean {
                              if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
                                  || TextUtils.isEmpty(signature)
                              ) {
                                  //Purchase verification failed: missing data
                                  return false
                              }
                              val key = generatePublicKey(base64PublicKey)
                              return verify(key, signedData, signature)
                          }
                      
                          /**
                           * Generates a PublicKey instance from a string containing the Base64-encoded public key.
                           *
                           * @param encodedPublicKey Base64-encoded public key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun generatePublicKey(encodedPublicKey: String): PublicKey {
                              return try {
                                  val decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT)
                                  val keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
                                  keyFactory.generatePublic(X509EncodedKeySpec(decodedKey))
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available.
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeySpecException) {
                                  val msg = "Invalid key specification: $e"
                                  throw IOException(msg)
                              }
                          }
                      
                          /**
                           * Verifies that the signature from the server matches the computed signature on the data.
                           * Returns true if the data is correctly signed.
                           *
                           * @param publicKey public key associated with the developer account
                           * @param signedData signed data from server
                           * @param signature server signature
                           * @return true if the data and signature match
                           */
                          private fun verify(publicKey: PublicKey, signedData: String, signature: String): Boolean {
                              val signatureBytes: ByteArray = try {
                                  Base64.decode(signature, Base64.DEFAULT)
                              } catch (e: IllegalArgumentException) {
                                  //Base64 decoding failed
                                  return false
                              }
                              try {
                                  val signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM)
                                  signatureAlgorithm.initVerify(publicKey)
                                  signatureAlgorithm.update(signedData.toByteArray())
                                  return signatureAlgorithm.verify(signatureBytes)
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeyException) {
                                  //Invalid key specification
                              } catch (e: SignatureException) {
                                  //Signature exception
                              }
                              return false
                          }
                      
                      }
                      
                      var inAppPurchase: InAppPurchase  = InAppPurchase(this)
                      btnInApp.setOnClickListener {
                                  inAppPurchase.productPurchase()
                              }
                      
                      implementation 'com.anjlab.android.iab.v3:library:1.1.0'
                      
                      implementation 'com.android.billingclient:billing:4.0.0'
                      
                      <string name="license_key">Place Your ID Here</string>
                      <string name="product_id">android.test.purchased</string>
                      
                      import android.app.Activity
                      import android.content.Context
                      import android.widget.Toast
                      import com.android.billingclient.api.*
                      import java.io.IOException
                      import java.util.ArrayList
                      
                      class InAppPurchase(context: Context) : PurchasesUpdatedListener{
                          private val mContext: Context = context
                          private var billingClient: BillingClient
                          var ackPurchase =
                              AcknowledgePurchaseResponseListener { billingResult ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      //if purchase is acknowledged
                                      // Grant entitlement to the user. and restart activity
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext, true)
                                      showMessage("Item Purchased")
                                      (mContext as Activity).recreate()
                                  }
                              }
                      
                          init {
                              billingClient =
                                  BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                              billingClient.startConnection(object : BillingClientStateListener {
                                  override fun onBillingSetupFinished(billingResult: BillingResult) {
                                      if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                          val queryPurchase = billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                          val queryPurchases = queryPurchase.purchasesList
                                          if (queryPurchases != null && queryPurchases.size > 0) {
                                              handlePurchases(queryPurchases)
                                          } else {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext, false)
                                          }
                                      }
                                  }
                      
                                  override fun onBillingServiceDisconnected() {}
                              })
                          }
                      
                          fun productPurchase() {
                              //check if service is already connected
                              if (billingClient.isReady) {
                                  initiatePurchase()
                              } else {
                                  billingClient =
                                      BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                                  billingClient.startConnection(object : BillingClientStateListener {
                                      override fun onBillingSetupFinished(billingResult: BillingResult) {
                                          if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                              initiatePurchase()
                                          } else {
                                              showMessage("Error" + billingResult.debugMessage)
                                          }
                                      }
                      
                                      override fun onBillingServiceDisconnected() {}
                                  })
                              }
                          }
                      
                          private fun initiatePurchase() {
                              val skuList: MutableList<String> = ArrayList()
                              skuList.add(mContext.resources.getString(R.string.product_id))
                              val params = SkuDetailsParams.newBuilder()
                              params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
                              billingClient.querySkuDetailsAsync(
                                  params.build()
                              ) { billingResult, skuDetailsList ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      if (skuDetailsList != null && skuDetailsList.size > 0) {
                                          val flowParams = BillingFlowParams.newBuilder()
                                              .setSkuDetails(skuDetailsList[0])
                                              .build()
                                          billingClient.launchBillingFlow(mContext as Activity, flowParams)
                                      } else {
                                          //try to add item/product id "purchase" inside managed product in google play console
                                          showMessage("Purchase Item not Found")
                                      }
                                  } else {
                                      showMessage(" Error " + billingResult.debugMessage)
                                  }
                              }
                          }
                      
                          /**
                           * Verifies that the purchase was signed correctly for this developer's public key.
                           *
                           * Note: It's strongly recommended to perform such check on your backend since hackers can
                           * replace this method with "constant true" if they decompile/rebuild your app.
                           *
                           */
                          private fun verifyValidSignature(signedData: String, signature: String): Boolean {
                              return try {
                                  // To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
                                  val base64Key = mContext.getString(R.string.license_key)
                                  Security.verifyPurchase(base64Key, signedData, signature)
                              } catch (e: IOException) {
                                  false
                              }
                          }
                      
                          fun handlePurchases(purchases: List<Purchase>) {
                              for (purchase in purchases) {
                                  //if item is purchased
                                  if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                                      if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
                                          // Invalid purchase
                                          // show error to user
                                         showMessage("Invalid Purchase")
                                          return
                                      }
                      //                 else purchase is valid
                      //                if item is purchased and not acknowledged
                                      if (!purchase.isAcknowledged) {
                                          val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                                              .setPurchaseToken(purchase.purchaseToken)
                                              .build()
                                          billingClient.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
                                      } else {
                                          // Grant entitlement to the user on item purchase
                                          // restart activity
                                          if (!SharedPreferencesUtils.getPurchasedBillingValue(mContext)) {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext,true)
                                              showMessage("Item Purchased")
                                              (mContext as Activity).recreate()
                                          }
                                      }
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
                                      showMessage("Purchase is Pending. Please complete Transaction")
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext,false)
                                      showMessage("Purchase Status Unknown")
                                  }
                              }
                      
                      
                          }
                      
                      
                          private fun showMessage(message: String) {
                              (mContext as Activity).runOnUiThread{
                                  Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
                              }
                      
                          }
                      
                          override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
                              //if item newly purchased
                              if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
                                  handlePurchases(purchases)
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
                                  val queryAlreadyPurchasesResult =
                                      billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                  val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
                                  alreadyPurchases?.let { handlePurchases(it) }
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
                                  showMessage("Purchase Canceled")
                              } else {
                                  showMessage("Error updated" + billingResult.debugMessage)
                              }
                          }
                      
                      
                          fun onDestroyBilling() {
                              billingClient.endConnection()
                          }
                      
                      }
                      
                      import android.text.TextUtils
                      import android.util.Base64
                      import java.io.IOException
                      import java.security.*
                      import java.security.spec.InvalidKeySpecException
                      import java.security.spec.X509EncodedKeySpec
                      
                      /**
                       * Security-related methods. For a secure implementation, all of this code should be implemented on
                       * a server that communicates with the application on the device.
                       */
                      object Security {
                      
                          private const val KEY_FACTORY_ALGORITHM = "RSA"
                          private const val SIGNATURE_ALGORITHM = "SHA1withRSA"
                      
                          /**
                           * Verifies that the data was signed with the given signature, and returns the verified
                           * purchase.
                           * @param base64PublicKey the base64-encoded public key to use for verifying.
                           * @param signedData the signed JSON string (signed, not encrypted)
                           * @param signature the signature for the data, signed with the private key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun verifyPurchase(
                              base64PublicKey: String, signedData: String,
                              signature: String
                          ): Boolean {
                              if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
                                  || TextUtils.isEmpty(signature)
                              ) {
                                  //Purchase verification failed: missing data
                                  return false
                              }
                              val key = generatePublicKey(base64PublicKey)
                              return verify(key, signedData, signature)
                          }
                      
                          /**
                           * Generates a PublicKey instance from a string containing the Base64-encoded public key.
                           *
                           * @param encodedPublicKey Base64-encoded public key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun generatePublicKey(encodedPublicKey: String): PublicKey {
                              return try {
                                  val decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT)
                                  val keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
                                  keyFactory.generatePublic(X509EncodedKeySpec(decodedKey))
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available.
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeySpecException) {
                                  val msg = "Invalid key specification: $e"
                                  throw IOException(msg)
                              }
                          }
                      
                          /**
                           * Verifies that the signature from the server matches the computed signature on the data.
                           * Returns true if the data is correctly signed.
                           *
                           * @param publicKey public key associated with the developer account
                           * @param signedData signed data from server
                           * @param signature server signature
                           * @return true if the data and signature match
                           */
                          private fun verify(publicKey: PublicKey, signedData: String, signature: String): Boolean {
                              val signatureBytes: ByteArray = try {
                                  Base64.decode(signature, Base64.DEFAULT)
                              } catch (e: IllegalArgumentException) {
                                  //Base64 decoding failed
                                  return false
                              }
                              try {
                                  val signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM)
                                  signatureAlgorithm.initVerify(publicKey)
                                  signatureAlgorithm.update(signedData.toByteArray())
                                  return signatureAlgorithm.verify(signatureBytes)
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeyException) {
                                  //Invalid key specification
                              } catch (e: SignatureException) {
                                  //Signature exception
                              }
                              return false
                          }
                      
                      }
                      
                      var inAppPurchase: InAppPurchase  = InAppPurchase(this)
                      btnInApp.setOnClickListener {
                                  inAppPurchase.productPurchase()
                              }
                      
                      implementation 'com.anjlab.android.iab.v3:library:1.1.0'
                      
                      implementation 'com.android.billingclient:billing:4.0.0'
                      
                      <string name="license_key">Place Your ID Here</string>
                      <string name="product_id">android.test.purchased</string>
                      
                      import android.app.Activity
                      import android.content.Context
                      import android.widget.Toast
                      import com.android.billingclient.api.*
                      import java.io.IOException
                      import java.util.ArrayList
                      
                      class InAppPurchase(context: Context) : PurchasesUpdatedListener{
                          private val mContext: Context = context
                          private var billingClient: BillingClient
                          var ackPurchase =
                              AcknowledgePurchaseResponseListener { billingResult ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      //if purchase is acknowledged
                                      // Grant entitlement to the user. and restart activity
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext, true)
                                      showMessage("Item Purchased")
                                      (mContext as Activity).recreate()
                                  }
                              }
                      
                          init {
                              billingClient =
                                  BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                              billingClient.startConnection(object : BillingClientStateListener {
                                  override fun onBillingSetupFinished(billingResult: BillingResult) {
                                      if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                          val queryPurchase = billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                          val queryPurchases = queryPurchase.purchasesList
                                          if (queryPurchases != null && queryPurchases.size > 0) {
                                              handlePurchases(queryPurchases)
                                          } else {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext, false)
                                          }
                                      }
                                  }
                      
                                  override fun onBillingServiceDisconnected() {}
                              })
                          }
                      
                          fun productPurchase() {
                              //check if service is already connected
                              if (billingClient.isReady) {
                                  initiatePurchase()
                              } else {
                                  billingClient =
                                      BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build()
                                  billingClient.startConnection(object : BillingClientStateListener {
                                      override fun onBillingSetupFinished(billingResult: BillingResult) {
                                          if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                              initiatePurchase()
                                          } else {
                                              showMessage("Error" + billingResult.debugMessage)
                                          }
                                      }
                      
                                      override fun onBillingServiceDisconnected() {}
                                  })
                              }
                          }
                      
                          private fun initiatePurchase() {
                              val skuList: MutableList<String> = ArrayList()
                              skuList.add(mContext.resources.getString(R.string.product_id))
                              val params = SkuDetailsParams.newBuilder()
                              params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
                              billingClient.querySkuDetailsAsync(
                                  params.build()
                              ) { billingResult, skuDetailsList ->
                                  if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                                      if (skuDetailsList != null && skuDetailsList.size > 0) {
                                          val flowParams = BillingFlowParams.newBuilder()
                                              .setSkuDetails(skuDetailsList[0])
                                              .build()
                                          billingClient.launchBillingFlow(mContext as Activity, flowParams)
                                      } else {
                                          //try to add item/product id "purchase" inside managed product in google play console
                                          showMessage("Purchase Item not Found")
                                      }
                                  } else {
                                      showMessage(" Error " + billingResult.debugMessage)
                                  }
                              }
                          }
                      
                          /**
                           * Verifies that the purchase was signed correctly for this developer's public key.
                           *
                           * Note: It's strongly recommended to perform such check on your backend since hackers can
                           * replace this method with "constant true" if they decompile/rebuild your app.
                           *
                           */
                          private fun verifyValidSignature(signedData: String, signature: String): Boolean {
                              return try {
                                  // To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
                                  val base64Key = mContext.getString(R.string.license_key)
                                  Security.verifyPurchase(base64Key, signedData, signature)
                              } catch (e: IOException) {
                                  false
                              }
                          }
                      
                          fun handlePurchases(purchases: List<Purchase>) {
                              for (purchase in purchases) {
                                  //if item is purchased
                                  if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                                      if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
                                          // Invalid purchase
                                          // show error to user
                                         showMessage("Invalid Purchase")
                                          return
                                      }
                      //                 else purchase is valid
                      //                if item is purchased and not acknowledged
                                      if (!purchase.isAcknowledged) {
                                          val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                                              .setPurchaseToken(purchase.purchaseToken)
                                              .build()
                                          billingClient.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
                                      } else {
                                          // Grant entitlement to the user on item purchase
                                          // restart activity
                                          if (!SharedPreferencesUtils.getPurchasedBillingValue(mContext)) {
                                              SharedPreferencesUtils.setPurchasedBillingValue(mContext,true)
                                              showMessage("Item Purchased")
                                              (mContext as Activity).recreate()
                                          }
                                      }
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
                                      showMessage("Purchase is Pending. Please complete Transaction")
                                  } else if (mContext.getString(R.string.product_id) == purchase.skus[0] && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
                                      SharedPreferencesUtils.setPurchasedBillingValue(mContext,false)
                                      showMessage("Purchase Status Unknown")
                                  }
                              }
                      
                      
                          }
                      
                      
                          private fun showMessage(message: String) {
                              (mContext as Activity).runOnUiThread{
                                  Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
                              }
                      
                          }
                      
                          override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
                              //if item newly purchased
                              if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
                                  handlePurchases(purchases)
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
                                  val queryAlreadyPurchasesResult =
                                      billingClient.queryPurchases(BillingClient.SkuType.INAPP)
                                  val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
                                  alreadyPurchases?.let { handlePurchases(it) }
                              } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
                                  showMessage("Purchase Canceled")
                              } else {
                                  showMessage("Error updated" + billingResult.debugMessage)
                              }
                          }
                      
                      
                          fun onDestroyBilling() {
                              billingClient.endConnection()
                          }
                      
                      }
                      
                      import android.text.TextUtils
                      import android.util.Base64
                      import java.io.IOException
                      import java.security.*
                      import java.security.spec.InvalidKeySpecException
                      import java.security.spec.X509EncodedKeySpec
                      
                      /**
                       * Security-related methods. For a secure implementation, all of this code should be implemented on
                       * a server that communicates with the application on the device.
                       */
                      object Security {
                      
                          private const val KEY_FACTORY_ALGORITHM = "RSA"
                          private const val SIGNATURE_ALGORITHM = "SHA1withRSA"
                      
                          /**
                           * Verifies that the data was signed with the given signature, and returns the verified
                           * purchase.
                           * @param base64PublicKey the base64-encoded public key to use for verifying.
                           * @param signedData the signed JSON string (signed, not encrypted)
                           * @param signature the signature for the data, signed with the private key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun verifyPurchase(
                              base64PublicKey: String, signedData: String,
                              signature: String
                          ): Boolean {
                              if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
                                  || TextUtils.isEmpty(signature)
                              ) {
                                  //Purchase verification failed: missing data
                                  return false
                              }
                              val key = generatePublicKey(base64PublicKey)
                              return verify(key, signedData, signature)
                          }
                      
                          /**
                           * Generates a PublicKey instance from a string containing the Base64-encoded public key.
                           *
                           * @param encodedPublicKey Base64-encoded public key
                           * @throws IOException if encoding algorithm is not supported or key specification
                           * is invalid
                           */
                          @Throws(IOException::class)
                          fun generatePublicKey(encodedPublicKey: String): PublicKey {
                              return try {
                                  val decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT)
                                  val keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
                                  keyFactory.generatePublic(X509EncodedKeySpec(decodedKey))
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available.
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeySpecException) {
                                  val msg = "Invalid key specification: $e"
                                  throw IOException(msg)
                              }
                          }
                      
                          /**
                           * Verifies that the signature from the server matches the computed signature on the data.
                           * Returns true if the data is correctly signed.
                           *
                           * @param publicKey public key associated with the developer account
                           * @param signedData signed data from server
                           * @param signature server signature
                           * @return true if the data and signature match
                           */
                          private fun verify(publicKey: PublicKey, signedData: String, signature: String): Boolean {
                              val signatureBytes: ByteArray = try {
                                  Base64.decode(signature, Base64.DEFAULT)
                              } catch (e: IllegalArgumentException) {
                                  //Base64 decoding failed
                                  return false
                              }
                              try {
                                  val signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM)
                                  signatureAlgorithm.initVerify(publicKey)
                                  signatureAlgorithm.update(signedData.toByteArray())
                                  return signatureAlgorithm.verify(signatureBytes)
                              } catch (e: NoSuchAlgorithmException) {
                                  // "RSA" is guaranteed to be available
                                  throw RuntimeException(e)
                              } catch (e: InvalidKeyException) {
                                  //Invalid key specification
                              } catch (e: SignatureException) {
                                  //Signature exception
                              }
                              return false
                          }
                      
                      }
                      
                      var inAppPurchase: InAppPurchase  = InAppPurchase(this)
                      btnInApp.setOnClickListener {
                                  inAppPurchase.productPurchase()
                              }
                      

                      Using an array from one function in another function in same fragment

                      copy iconCopydownload iconDownload
                       @BindView(R.id.customCarouselView) CarouselView customCarouselView; //butterknife
                      
                      
                         double[] sampleVotes = {
                                  8.9,4.2,
                          };
                      
                          List<String> sampleTitles = new ArrayList<String>(); //declare as global variable so you can access it
                      
                          @Override
                              public void onCreate (@Nullable Bundle savedInstanceState) {
                                  super.onCreate (savedInstanceState);
                          
                          connect();
                          }
                      
                         private void connect() {
                      
                          //Do your insert operations in array here 
                              sampleTitles.add("Test 1");
                              sampleTitles.add("Test 2");
                                              
                              customCarouselView.setViewListener(viewListener);
                      
                          }
                      
                         // To set custom views
                          ViewListener viewListener = new ViewListener() {
                              @Override
                              public View setViewForPosition(int position) {
                      
                                  View customView = getLayoutInflater().inflate(R.layout.view_custom, null);
                      
                                  TextView labelTextView = customView.findViewById(R.id.labelTextView);
                                
                                  labelTextView.setText(sampleTitles.get(position));  //you can access your array with this code               
                      
                                  return customView;
                              }
                          };
                      

                      Adding a fragment and calling .replace() causing a memory leak in the added fragment

                      copy iconCopydownload iconDownload
                          public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                              View view = inflater.inflate(R.layout.fragment_admin_deactivate_user, container, false);
                              unbinder=ButterKnife.bind(this, view);//initialise the unbinder here
                      
                      
                            return view;
                          }
                      
                          Override
                          public void onDestroyView() {
                          Log.d(TAG, "onDestroyView: Called");
                        
                          if(unbinder!=null){
                              unbinder.unbind();
                              unbinder = null;
                          }
                         
                          super.onDestroyView();
                          }
                      
                           @Override
                              public void onDestroyView() {
                              recyclerView.setAdapter(null);
                             super.onDestroyView();
                           }
                      
                          public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                              View view = inflater.inflate(R.layout.fragment_admin_deactivate_user, container, false);
                              unbinder=ButterKnife.bind(this, view);//initialise the unbinder here
                      
                      
                            return view;
                          }
                      
                          Override
                          public void onDestroyView() {
                          Log.d(TAG, "onDestroyView: Called");
                        
                          if(unbinder!=null){
                              unbinder.unbind();
                              unbinder = null;
                          }
                         
                          super.onDestroyView();
                          }
                      
                           @Override
                              public void onDestroyView() {
                              recyclerView.setAdapter(null);
                             super.onDestroyView();
                           }
                      
                          @Override
                          public void onCreate(@Nullable Bundle savedInstanceState) {
                              super.onCreate(savedInstanceState);
                              mContext = getContext();
                      
                          }
                      
                          @Override
                          public void onDestroy() {
                              mContext = null;
                              super.onDestroy();
                          }
                      
                          @Override
                          public void onCreate(@Nullable Bundle savedInstanceState) {
                              super.onCreate(savedInstanceState);
                              mContext = getContext();
                      
                          }
                      
                          @Override
                          public void onDestroy() {
                              mContext = null;
                              super.onDestroy();
                          }
                      
                      private Unbinder unbinder;
                      
                      @Nullable
                          @Override
                          public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                              View view = inflater.inflate(R.layout.fragment_admin_link_family, container, false);
                              
                              return view;
                          }
                      
                      Inside Adapter class
                      
                      
                       class ViewHolder extends RecyclerView.ViewHolder {
                      
                              @BindView(R.id.action_type)
                              TextView userAction;
                              @BindView(R.id.date)
                              TextView date;
                              @BindView(R.id.amount)
                              TextView amount;
                      
                              ViewHolder(@NonNull View itemView) {
                                  super(itemView);
                                  ButterKnife.bind(this, itemView);
                              }
                          }
                      
                      Fragment Class
                      
                      @Override
                          public void onDestroyView() {
                              super.onDestroyView();
                              adapter = null;
                              unbinder.unbind();
                      }
                      
                      private Unbinder unbinder;
                      
                      @Nullable
                          @Override
                          public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                              View view = inflater.inflate(R.layout.fragment_admin_link_family, container, false);
                              
                              return view;
                          }
                      
                      Inside Adapter class
                      
                      
                       class ViewHolder extends RecyclerView.ViewHolder {
                      
                              @BindView(R.id.action_type)
                              TextView userAction;
                              @BindView(R.id.date)
                              TextView date;
                              @BindView(R.id.amount)
                              TextView amount;
                      
                              ViewHolder(@NonNull View itemView) {
                                  super(itemView);
                                  ButterKnife.bind(this, itemView);
                              }
                          }
                      
                      Fragment Class
                      
                      @Override
                          public void onDestroyView() {
                              super.onDestroyView();
                              adapter = null;
                              unbinder.unbind();
                      }
                      
                      private Unbinder unbinder;
                      
                      @Nullable
                          @Override
                          public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                              View view = inflater.inflate(R.layout.fragment_admin_link_family, container, false);
                              
                              return view;
                          }
                      
                      Inside Adapter class
                      
                      
                       class ViewHolder extends RecyclerView.ViewHolder {
                      
                              @BindView(R.id.action_type)
                              TextView userAction;
                              @BindView(R.id.date)
                              TextView date;
                              @BindView(R.id.amount)
                              TextView amount;
                      
                              ViewHolder(@NonNull View itemView) {
                                  super(itemView);
                                  ButterKnife.bind(this, itemView);
                              }
                          }
                      
                      Fragment Class
                      
                      @Override
                          public void onDestroyView() {
                              super.onDestroyView();
                              adapter = null;
                              unbinder.unbind();
                      }
                      
                      private Unbinder unbinder;
                      
                      @Nullable
                          @Override
                          public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                              View view = inflater.inflate(R.layout.fragment_admin_link_family, container, false);
                              
                              return view;
                          }
                      
                      Inside Adapter class
                      
                      
                       class ViewHolder extends RecyclerView.ViewHolder {
                      
                              @BindView(R.id.action_type)
                              TextView userAction;
                              @BindView(R.id.date)
                              TextView date;
                              @BindView(R.id.amount)
                              TextView amount;
                      
                              ViewHolder(@NonNull View itemView) {
                                  super(itemView);
                                  ButterKnife.bind(this, itemView);
                              }
                          }
                      
                      Fragment Class
                      
                      @Override
                          public void onDestroyView() {
                              super.onDestroyView();
                              adapter = null;
                              unbinder.unbind();
                      }
                      

                      Community Discussions

                      Trending Discussions on butterknife
                      • Firebase crashlytics not able to read crash reports
                      • Gradle Failure A problem occurred evaluating project ':app' after update android Studio
                      • PopupWindow .showAsDropDown() unable to shift left or right (But up and down both work)
                      • Which lifecycle method should I place my network call so it doesn't get called again when the screen rotates?
                      • Can not run the the tflite model on Interpreter in android studio
                      • How to fix gradle which stopped working - error while syncing?
                      • Duplicate class in build.gradle file
                      • What is this Error when Debug android app?
                      • Library to change to fix Google app publish error; Billing Library version 3 in android studio
                      • How can i solve this error in android studio? java.lang.IllegalStateException: Required view 'recycler_food_list'
                      Trending Discussions on butterknife

                      QUESTION

                      Firebase crashlytics not able to read crash reports

                      Asked 2022-Apr-11 at 14:08

                      I have configured crashlytics as per Firebase Documentation https://firebase.google.com/docs/crashlytics/get-started?platform=android. But crash reports not generated and uploaded to server.

                      server

                      Kindly refer my build details.

                      Here is our project-level build.gradle

                      buildscript {
                          
                          repositories {
                              google()
                              jcenter()
                      
                              mavenCentral()
                          }
                          dependencies {
                              classpath 'com.android.tools.build:gradle:4.2.1'
                              classpath 'com.google.gms:google-services:4.3.10'
                              classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
                      
                          }
                      }
                      
                      allprojects {
                          repositories {
                              google()
                              jcenter()
                              maven { url 'https://jitpack.io'}
                              maven{ url 'https://maven.google.com/' }
                              mavenCentral()
                      
                              flatDir {
                                  dirs 'libs'
                              }
                          }
                      }
                      
                      task clean(type: Delete) {
                          delete rootProject.buildDir
                      }
                      

                      build.gradle(:app)

                      apply plugin: 'com.android.application'
                      apply plugin: 'com.google.gms.google-services'
                      apply plugin: 'com.google.firebase.crashlytics'
                      
                      android {
                      
                          compileSdkVersion 28
                          defaultConfig {
                              applicationId "com.XXX.XXX"
                              minSdkVersion 21
                              targetSdkVersion 28
                              versionCode 375
                              versionName "2.25.1"
                      
                              multiDexEnabled true
                              testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
                              dataBinding {
                                  enabled = true
                              }
                              signingConfig signingConfigs.config
                          }
                      
                          android {
                              lintOptions {
                                  checkReleaseBuilds false
                                  abortOnError false
                              }
                          }
                      
                          flavorDimensions "appVariant", "projectCode"
                          productFlavors {
                              A {
                                  applicationId 'com.XXX.A'
                                  dimension "appVariant"
                              }
                              B {
                                  applicationId 'com.XXX.B'
                                  dimension "appVariant"
                              }
                              C {
                                  applicationId 'com.XXX.C'
                                  dimension "appVariant"
                              }
                              D {
                                  applicationId 'com.XXX.D'
                                  dimension "appVariant"
                              }
                              DEV {
                                  dimension "projectCode"
                              }
                              QA {
                                  dimension "projectCode"
                              }
                              LIVE {
                                  dimension "projectCode"
                              }
                              DEMO {
                                  dimension "projectCode"
                              }
                              BETA {
                                  dimension "projectCode"
                              }
                          }
                      
                          applicationVariants.all { variant ->
                              variant.outputs.all { output ->
                                  def project = "XXX"
                                  def SEP = "_"
                                  def flavor = variant.productFlavors[0].name
                                  def projcode = variant.productFlavors[1].name
                                  def buildType = variant.buildType.name
                                  def buildTypeName = "";
                                  switch (buildType) {
                                      case "ABC": buildTypeName = SEP + "AB"; break;
                                      case "XYZ": buildTypeName = SEP + "XY"; break;
                                      default:
                                          buildTypeName = "";
                                  }
                      
                                  def version = variant.versionName
                                  def newApkName = project + buildTypeName + SEP + flavor + SEP + projcode + SEP + version + ".apk"
                      
                                  outputFileName = new File(newApkName)
                              }
                          }
                      
                          compileOptions {
                              sourceCompatibility JavaVersion.VERSION_1_8
                              targetCompatibility JavaVersion.VERSION_1_8
                          }
                      
                          buildTypes {
                              debug {
                      
                                  minifyEnabled false
                                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                                  signingConfig signingConfigs.config
                                  buildConfigField "String", "AREA", "\"\""
                              }
                              
                              release {
                                  minifyEnabled false
                                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                                  signingConfig signingConfigs.config
                                  buildConfigField "String", "AREA", "\"\""
                              }
                              ABC {
                                  signingConfig signingConfigs.config
                                  minifyEnabled false
                                  buildConfigField "String", "AREA", "\"_A\""
                              }
                              XYZ {
                                  signingConfig signingConfigs.config
                                  minifyEnabled false
                                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                                  signingConfig signingConfigs.config
                                  buildConfigField "String", "AREA", "\"_X\""
                              }
                          }
                          
                          packagingOptions {
                              exclude 'META-INF/DEPENDENCIES.txt'
                              exclude 'META-INF/LICENSE.txt'
                              exclude 'META-INF/NOTICE.txt'
                              exclude 'META-INF/NOTICE'
                              exclude 'META-INF/LICENSE'
                              exclude 'META-INF/DEPENDENCIES'
                              exclude 'META-INF/notice.txt'
                              exclude 'META-INF/license.txt'
                              exclude 'META-INF/dependencies.txt'
                              exclude 'META-INF/LGPL2.1'
                          }
                      }
                      
                      repositories {
                      
                          maven {
                              url 'https://maven.google.com/'
                              name 'Google'
                          }
                      
                      }
                      
                      dependencies {
                          def room_version = "1.1.1"
                          def lifecycle_version = "1.1.1"
                          def work_version = "1.0.0-beta01"
                          implementation files('libs/commons-net-3.3.jar')
                          implementation files('libs/httpclient-4.3.4.jar')
                          implementation files('libs/httpcore-4.3.2.jar')
                          implementation files('libs/httpmime-4.3.4.jar')
                          implementation files('libs/silipmlib.jar')
                          implementation files('libs/HyperLogLib8.jar')
                          
                          // Import the BoM for the Firebase platform
                          implementation platform('com.google.firebase:firebase-bom:29.3.0')
                          
                          implementation 'com.google.firebase:firebase-crashlytics'
                          implementation 'com.google.firebase:firebase-analytics'
                          implementation 'com.google.firebase:firebase-messaging'
                      
                          //dependency for Workmanager
                          implementation 'androidx.work:work-runtime:2.0.1'
                      
                          //dependencies for Room database
                          implementation 'androidx.room:room-runtime:2.0.0'
                          //noinspection GradleCompatible
                          implementation 'androidx.legacy:legacy-support-v4:1.0.0'
                          annotationProcessor 'androidx.room:room-compiler:2.0.0'
                          implementation fileTree(include: ['*.jar'], dir: 'libs')
                          implementation 'androidx.appcompat:appcompat:1.0.0'
                          implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
                          implementation 'com.google.android.material:material:1.0.0'
                          //dependency for custom progress dialog
                      
                          //dependency for retrofit
                          implementation 'com.squareup.retrofit2:retrofit:2.4.0'
                          implementation 'com.google.code.gson:gson:2.8.0'
                          implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
                      
                          //dependency for joda time for date time calculation
                          implementation 'joda-time:joda-time:2.10'
                      
                          //dependency for glide
                          implementation 'com.github.bumptech.glide:glide:3.7.0'
                      
                          //dependency for custom toast
                          implementation 'com.valdesekamdem.library:md-toast:0.9.0'
                      
                          //dependency for marshmallow permission - dexter library
                          implementation 'com.karumi:dexter:4.2.0'
                      
                          // ViewModel and LiveData
                          implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
                          annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.0.0'
                      
                          // alternately - if using Java8, use the following instead of compiler
                          implementation 'androidx.lifecycle:lifecycle-common-java8:2.0.0'
                      
                          implementation 'com.jakewharton:butterknife:10.1.0'
                          annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
                      
                          androidTestImplementation 'androidx.test.ext:junit:1.1.1'
                          androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
                          implementation project(':floatingmenu')
                          implementation project(':html2bitmap')
                          debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
                          implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
                          implementation 'com.github.vipulasri:timelineview:1.0.6'
                          implementation 'me.relex:circleindicator:1.2.2@aar'
                          implementation 'com.haozhang.libary:android-slanted-textview:1.2'
                          implementation 'com.google.android.gms:play-services-maps:15.0.1'
                          implementation 'com.google.android.gms:play-services-location:15.0.1'
                      
                          // implementation 'com.google.android.gms:play-services-gcm:11.8.0'
                      
                          // implementation 'com.google.android.gms:play-services-ads:11.8.0'
                          implementation('com.github.florent37:materialviewpager:1.2.3') {
                              exclude group: 'com.android.support'
                          }
                      
                          implementation 'com.orhanobut:dialogplus:1.11@aar'
                      
                          //  implementation 'me.dm7.barcodescanner:zbar:1.8.4'
                          implementation 'me.dm7.barcodescanner:zxing:1.9'
                          implementation 'com.journeyapps:zxing-android-embedded:2.3.0@aar'
                          implementation 'com.journeyapps:zxing-android-legacy:2.3.0@aar'
                          implementation 'com.journeyapps:zxing-android-integration:2.3.0@aar'
                          implementation 'com.google.zxing:core:3.2.0'
                          implementation 'net.cachapa.expandablelayout:expandablelayout:2.9.2'
                          implementation 'com.github.siyamed:android-shape-imageview:0.9.+@aar'
                          implementation files('libs/HyperLogLib8.jar')
                          implementation project(':scandecode-release')
                          implementation 'com.tt:whorlviewlibrary:1.0.3'
                          implementation 'io.reactivex:rxandroid:1.2.1'
                          implementation 'io.reactivex:rxjava:1.1.6'
                          implementation 'com.jakewharton.rxbinding:rxbinding:0.4.0'
                          implementation 'com.jakewharton.rxbinding:rxbinding-design:0.4.0'
                      
                          implementation 'org.apache.commons:commons-text:1.7'
                      
                          // these are for retrolambda and streams api
                          implementation 'com.annimon:stream:1.1.2'
                      
                      }
                      
                      

                      With initialisation:

                      FirebaseApp.initializeApp(this)
                      FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
                      

                      And manifest:

                      <meta-data
                                  android:name="firebase_crashlytics_collection_enabled"
                                  android:value="true" />
                      

                      Here is the logcat for the Crashlytics/CrashTest crash:

                      2022-04-10 15:53:07.717 21310-21310/com.XXX.XXX E/AndroidRuntime: FATAL EXCEPTION: main
                          Process: com.XXX.XXX, PID: 21310
                          java.lang.RuntimeException: Test Crash
                              at com.XXX.XXX.UI.HomeActivity$1.onClick(HomeActivity.java:345)
                              at android.view.View.performClick(View.java:6392)
                              at android.view.View$PerformClick.run(View.java:25133)
                              at android.os.Handler.handleCallback(Handler.java:790)
                              at android.os.Handler.dispatchMessage(Handler.java:99)
                              at android.os.Looper.loop(Looper.java:198)
                              at android.app.ActivityThread.main(ActivityThread.java:7055)
                              at java.lang.reflect.Method.invoke(Native Method)
                              at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:523)
                              at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:836)
                      

                      This is the log that we receive when app relaunched after crash.

                      D:\user\Android Projects\XXX>adb logcat -s FirebaseCrashlytics
                      --------- beginning of main
                      --------- beginning of system
                      --------- beginning of crash
                      04-10 15:54:56.911 22018 22018 I FirebaseCrashlytics: Initializing Firebase Crashlytics 18.2.9 for com.XXX.XXX
                      04-10 15:54:56.926 22018 22018 D FirebaseCrashlytics: Crashlytics automatic data collection ENABLED by API.
                      04-10 15:54:56.940 22018 22018 D FirebaseCrashlytics: AnalyticsConnector now available.
                      04-10 15:54:56.943 22018 22018 D FirebaseCrashlytics: Registered Firebase Analytics listener.
                      04-10 15:54:56.948 22018 22018 D FirebaseCrashlytics: Mapping file ID is: 00000000000000000000000000000000
                      04-10 15:54:56.958 22018 22018 D FirebaseCrashlytics: Checking for cached settings...
                      04-10 15:54:56.992 22018 22018 D FirebaseCrashlytics: Loaded cached settings: {"settings_version":3,"cache_duration":86400,"features":{"collect_logged_exceptions":true,"collect_reports":
                      true,"collect_analytics":false,"prompt_enabled":false,"push_enabled":false,"firebase_crashlytics_enabled":false,"collect_anrs":true,"collect_metric_kit":false},"app":{"status":"activated
                      ","update_required":false,"report_upload_variant":2,"native_report_upload_variant":2},"fabric":{"org_id":"62513aa60277ea5e0396d4ef","bundle_id":"com.XXX.XXX"},"on_demand_
                      upload_rate_per_minute":10,"on_demand_backoff_base":1.2,"on_demand_backoff_step_duration_seconds":60,"expires_at":1649666891559}
                      04-10 15:54:56.996 22018 22018 D FirebaseCrashlytics: Crashlytics automatic data collection ENABLED by API.
                      04-10 15:54:57.113 22018 22018 D FirebaseCrashlytics: Successfully configured exception handler.
                      04-10 15:54:57.116 22018 22049 D FirebaseCrashlytics: Opening a new session with ID 6252B07803E20001560228F94565CB5E
                      04-10 15:54:57.183 22018 22049 D FirebaseCrashlytics: Registered Firebase Analytics event receiver for breadcrumbs
                      04-10 15:54:58.013 22018 22018 D FirebaseCrashlytics: Crashlytics automatic data collection ENABLED by API.
                      04-10 15:54:58.642 22018 22018 D FirebaseCrashlytics: Crashlytics automatic data collection ENABLED by API.
                      

                      These are set to false in cached settings:

                      "collect_analytics":false,
                      "firebase_crashlytics_enabled":false,
                      

                      This setting was weird. Both of them are false for some reason though I never did turn them off explicitly. Never even played with these settings.

                      Not sure what is wrong. Any help will be appreciated.

                      ANSWER

                      Answered 2022-Apr-11 at 14:08

                      Solved!..
                      There was another utility logger library initialized in the application class that prevented crashlytics from collecting log. https://github.com/hypertrack/hyperlog-android

                      Also the initialization & manifest part is not necessary unless you want to explicitly enable/disable crashlytics working.

                      Source https://stackoverflow.com/questions/71815836

                      Community Discussions, Code Snippets contain sources that include Stack Exchange Network

                      Vulnerabilities

                      No vulnerabilities reported

                      Install butterknife

                      If you are using Kotlin, replace annotationProcessor with kapt. Snapshots of the development version are available in [Sonatype’s snapshots repository][snap].

                      Support

                      For any new features, suggestions and bugs create an issue on GitHub. If you have any questions check and ask questions on community page Stack Overflow .

                      DOWNLOAD this Library from

                      Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from
                      over 430 million Knowledge Items
                      Find more libraries
                      Reuse Solution Kits and Libraries Curated by Popular Use Cases
                      Explore Kits

                      Save this library and start creating your kit

                      Explore Related Topics

                      Share this Page

                      share link
                      Consider Popular Android Libraries
                      Try Top Libraries by JakeWharton
                      Compare Android Libraries with Highest Support
                      Compare Android Libraries with Highest Quality
                      Compare Android Libraries with Highest Security
                      Compare Android Libraries with Permissive License
                      Compare Android Libraries with Highest Reuse
                      Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from
                      over 430 million Knowledge Items
                      Find more libraries
                      Reuse Solution Kits and Libraries Curated by Popular Use Cases
                      Explore Kits

                      Save this library and start creating your kit

                      • © 2022 Open Weaver Inc.