Flutter release apk can't proceed payment in PayHere

224

Solution 1

Root Cause

The issue is caused by Flutter’s R8 code shrinking which is turned on by default for Release builds as stated here. Since Android Gradle version 3.4.0, R8 does not use Proguard under the hood as mentioned here. However, R8 still uses the proguard rule files in the exact format, to exclude classes from being obfuscated/removed only if explicitly provided. Otherwise, unused code will be stripped out of the final product.

It is understood that the MethodChannels used internally by Flutter and Dart to link between the PayHere Android SDK and PayHere Flutter Dart components are affected by this code obfuscation process.

Solution

There are two solutions to resolving the issue. The first offers more flexibility down the line, should developers extend the existing codebase. The second solution is a quick “hotfix”, which disables code obfuscation in favor of ease of applicability.

NOTE: Please maintain a backup of your existing codebase before carrying out the solutions mentioned hereafter. This step is recommended even if you have version control enabled, since .gitignore definitions might not track changes to files carrying sensitive information.

1. Solution using Android Proguard Rules

This solution is preferred if you are comfortable creating Pro-guard rule files manually or you have already configured Pro-guard rules. The steps required are mentioned below.

  1. Open your Flutter Project in your preferred IDE.

  2. Create a new file named, “proguard-rules.pro” in the “/android/app” folder.

    screenshot

  3. Add the following lines of code in the “proguard-rules.pro” file created in Step 2 above.

    #Flutter Wrapper
    -keep class io.flutter.app.** { *; } 
    -keep class io.flutter.plugin.** { *; } 
    -keep class io.flutter.util.** { *; } 
    -keep class io.flutter.view.** { *; } 
    -keep class io.flutter.** { *; }
    -keep class io.flutter.plugins.** { *; } 
    
    #the required rule
    -keep class lk.payhere.** { *; }
    

The above code excludes all default Flutter libraries and the PayHere Android SDK classes. Make sure you do not have overlapping rules. If you already had an existing “proguard-rules.pro” file, only add the last line.

  1. Open the “build.gradle” file located in the “/android/app” folder.
  2. Find the “buildTypes” block inside the top-level “android” block. Note that in the context of this issue, developers are building the Flutter App for release mode and should already have the “buildTypes” block written.
  3. Instruct the Android Build system to keep code minification/obfuscation turned on, and to use your Proguard rules defined in Step 3 using the following highlighted code.

Note that if you have already set up Proguard previously, you might be able to skip this step.

android {
  compileSdkVersion 29
   sourceSets {
     main.java.srcDirs += 'src/main/kotlin'
  }
   lintOptions {
     disable 'InvalidPackage'
  }
   defaultConfig {
     // Android configurations are usually here
  }
   // Signing Configurations are usually here
   buildTypes {
     release {
       signingConfig signingConfigs.debug

       // add these code lines
       minifyEnabled true
       useProguard true
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    } 
  }
}
  1. Perform a Flutter clean task and build your Release APK. Your issue should be resolved now.

2. Solution by disabling modification

If you do not require code obfuscation or minification in your Release APK, you can simply disable this feature altogether for the Android code. The required steps are mentioned below.

  1. Open up your Flutter Project in your preferred IDE

  2. Open the “build.gradle” file in the “/android/app” folder.

  3. Find the “android” block, within it locate the “buildTypes” and “release” blocks.

  4. Add the following mentioned code to disable code modification.

    android {
        compileSdkVersion 29
        sourceSets {
            main.java.srcDirs += 'src/main/kotlin'
        }
    
        lintOptions {
            disable 'InvalidPackage'
        }
    
        defaultConfig {
            // Android configurations are usually here
        }
        // Signing Configurations are usually here
        buildTypes {
            release {
                signingConfig signingConfigs.debug
    
                // add these code lines
                minifyEnabled false
                shrinkResources false
            } 
        }
    }
    
  5. Perform a Flutter clean task and build your Release APK. Your issue should be resolved now.

Happy coding :D

Solution 2

Most likely this is an issue with Android's code minification on Release builds. The proposed solution is to try and prevent the PayHere code from getting stripped in Release builds, by adding proper ProGuard rules.

Adding the ProGuard Rule

  1. In your Flutter project Directory, find the "android" folder.
  2. Navigate to the "app" subfolder.
  3. Create a new file named "proguard-rules.pro" if it does not already exist.
  4. Open the above ProGuard file in your text editor.
  5. Copy and paste the following line to the end of the ProGuard file (this will exclude all classes related to the PayHere SDKs from code shrinking/minifcation).
-keep class lk.payhere.** { *; }

Instructing Android to use the ProGuard file

  1. Open the "android/app/build.gradle" file.
  2. Find the buildTypes > release block.
  3. If not already there, add the following lines.
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

The final result in the "build.gradle" file should look something like this:

android {
 compileSdkVersion 29

  // ...

  buildTypes {
    release {

      signingConfig signingConfigs.debug

      // the code we added...

      minifyEnabled true
      useProguard true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

    }
  }
}

Finally,

Do a clean build and see if your issue is resolved.

If the issue still persists, try adding an Alert popup in the PayHere Flutter SDK's error handler to see if a readable error is returned.

Something like:

PayHere.startPayment(
  paymentObject, 
  (paymentId) {
    print("One Time Payment Success. Payment Id: $paymentId");
  }, 
  (error) { 
    print("One Time Payment Failed. Error: $error");
    // add alert code here
  }, 
  () { 
    print("One Time Payment Dismissed");
  }
);

Last resort would be to contact PayHere themselves for support. If that is the case, you can mail them at [email protected]


Note that ProGuard rules also work with Android's R8 code shrinking as per the documentation.

When building the release version of your app, by default, R8 automatically performs the compile-time tasks described above for you. However, you can disable certain tasks or customize R8’s behavior through ProGuard rules files. In fact, R8 works with all of your existing ProGuard rules files, so updating the Android Gradle plugin to use R8 should not require you to change your existing rules.

Share:
224
Rajitha Udayanga
Author by

Rajitha Udayanga

Updated on December 11, 2022

Comments

  • Rajitha Udayanga
    Rajitha Udayanga over 1 year

    My flutter app can't proceed with payment in the PayHere payment gateway in the release apk. In the debug mode and run the app in release mode working fine. but only getting an error when build and running release apk.