Android Custom Browser

Version 5.3


Welcome to the Android-Custom-Browser wiki!

Screenshots:

Integration:

1. Download the CustomBrowser-release.aar file from github. Rename it to CustomBrowser.aar

2. Import CustomBrowser as a module.

3. Make sure that app has a module dependency on CustomBrowser.

4. Grant following permission in AndroidManifest.xml file.

mandatory:

      <uses-permission android:name="android.permission.RECEIVE_SMS" />

non-mandatory:

     <uses-permissiones-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

5. Assign the layout as given below to your activity

    <RelativeLayout
         xmlns:android="https://schemas.android.com/apk/res/android"
         android:id="@+id/r_layout"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:gravity="center_horizontal">
    <FrameLayout
         android:id="@+id/parent"
         android:visibility="gone"
         android:layout_alignParentBottom="true"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"/>
    <WebView
         android:id="@+id/webview"
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
    <!-- Magic retry-->
      <LinearLayout
       android:layout_centerInParent="true"
       android:orientation="vertical"
       android:id="@+id/magic_retry_container"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
     </LinearLayout>
     <LinearLayout
       android:layout_width="match_parent"
       android:id="@+id/trans_overlay"
       android:layout_height="match_parent"
       android:orientation="horizontal"
       android:background="@drawable/background_drawable">
     </LinearLayout>
     </RelativeLayout>

Note:

  • id of frame layout should be parent
  • default visibility of frame layout should be “gone”. CustomBrowser will handle the same.
  1. Make sure that your Activity is able to support Fragments (v7 support library)

  2. Inside your activity add the required code so that it will look something like this

    Note:

    • Please make sure to change R.id.webiew to the id of your webview
    • You can override the default functions of PayUWebViewClient (same as that of webview client)
    • To enable auto select OTP and auto approve

      args.putBoolean(Bank.AUTO_SELECT_OTP, true); args.putBoolean(Bank.AUTO_APPROVE, true);

    • To read SMS in Android M

      args.putBoolean(Bank.MERCHANT_SMS_PERMISSION, true);

    • To enable auto select OTP and auto approve

      args.putInt(Bank.STORE_ONE_CLICK_HASH, storeOneClickHash);

    • where storeOneCickHash can be any one of the following.

      0 - None (default, PayUConstants.STORE_ONE_CLICK_HASH_NONE).

      1 - store one click hash in merchant's server (recommended, PayUConstants.STORE_ONE_CLICK_HASH_SERVER).

      2 - store one click hash in device memory (PayuConstants.STORE_ONE_CLICK_HASH_MOBILE).

In Activity

 @Override
protected void onCreate(Bundle savedInstanceState) {
    /**
     * when the device runing out of memory we dont want the user to restart the payment. rather we close it and redirect them to previous activity.
     */

    if(savedInstanceState!=null){
        super.onCreate(null);
        finish();//call activity u want to as activity is being destroyed it is restarted
    }else {
        super.onCreate(savedInstanceState);
    }
    setContentView(R.layout.activity_payments);
    mWebView = (WebView) findViewById(R.id.webview);

    bundle = getIntent().getExtras();
    payuConfig = bundle.getParcelable(PayuConstants.PAYU_CONFIG);
    url = payuConfig.getEnvironment() == PayuConstants.PRODUCTION_ENV?  PayuConstants.PRODUCTION_PAYMENT_URL : PayuConstants.MOBILE_TEST_PAYMENT_URL ;

    String [] list =  payuConfig.getData().split("&");
    String txnId = null;
    String merchantKey = null;
    for (String item : list) {
        String[] items = item.split("=");
        if(items.length >= 2) {
            String id = items[0];
            switch (id) {
                case "txnid":
                    txnId = items[1];
                    break;
                case "key":
                    merchantKey = items[1];
                    break;
                case "pg":
                    if (items[1].contentEquals("NB")) {
                        viewPortWide = true;
                    }
                    break;
            }
        }
    }

    try {
        Class.forName("com.payu.custombrowser.Bank");
        final Bank bank = new Bank() {
            @Override
            public void registerBroadcast(BroadcastReceiver broadcastReceiver, IntentFilter filter) {
                mReceiver = broadcastReceiver;
                registerReceiver(broadcastReceiver, filter);
            }

            @Override
            public void unregisterBroadcast(BroadcastReceiver broadcastReceiver) {
                if(mReceiver != null){
                    unregisterReceiver(mReceiver);
                    mReceiver = null;
                }
            }

            @Override
            public void onHelpUnavailable() {
                findViewById(R.id.parent).setVisibility(View.GONE);
                findViewById(R.id.trans_overlay).setVisibility(View.GONE);
            }

            @Override
            public void onBankError() {
                findViewById(R.id.parent).setVisibility(View.GONE);
                findViewById(R.id.trans_overlay).setVisibility(View.GONE);
            }

            @Override
            public void onHelpAvailable() {
                findViewById(R.id.parent).setVisibility(View.VISIBLE);
            }
        };
        Bundle args = new Bundle();
        args.putInt(Bank.WEBVIEW, R.id.webview);
        args.putInt(Bank.TRANS_LAYOUT, R.id.trans_overlay);
        args.putInt(Bank.MAIN_LAYOUT, R.id.r_layout);
        args.putBoolean(Bank.VIEWPORTWIDE, viewPortWide);

        args.putString(Bank.TXN_ID, txnId == null ? String.valueOf(System.currentTimeMillis()) : txnId);
        args.putString(Bank.MERCHANT_KEY, null != merchantKey ? merchantKey : "could not find");
        PayUSdkDetails payUSdkDetails = new PayUSdkDetails();
        args.putString(Bank.SDK_DETAILS, payUSdkDetails.getSdkVersionName());
        if(getIntent().getExtras().containsKey("showCustom")) {
            args.putBoolean(Bank.SHOW_CUSTOMROWSER, getIntent().getBooleanExtra("showCustom", false));
        }
        args.putBoolean(Bank.SHOW_CUSTOMROWSER, true);
        args.putBoolean(Bank.MERCHANT_SMS_PERMISSION, true);//set true for android M,false otherwise
        args.putBoolean(Bank.AUTO_SELECT_OTP, true); // enable auto opt click in choose page
        args.putBoolean(Bank.AUTO_APPROVE, true); // enable auto approve as soon as otp received
        args.putInt(Bank.STORE_ONE_CLICK_HASH, PayUConstants.STORE_ONE_CLICK_HASH_SERVER);
        bank.setArguments(args);
        findViewById(R.id.parent).bringToFront();
        try {
            getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.fade_in, R.anim.cb_face_out).add(R.id.parent, bank).commit();
        }catch(Exception e)
        {
            e.printStackTrace();
            finish();
        }
        mWebView.setWebChromeClient(new PayUWebChromeClient(bank));
        mWebView.setWebViewClient(new PayUWebViewClient(bank));
        mWebView.postUrl(url, payuConfig.getData().getBytes());

        // add if using PayU SDK
         (new PayuUtils()).deviceAnalytics(PaymentsActivity.this, Bank.Version, merchantKey, txnId);
    } catch (ClassNotFoundException e) {
        mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
        mWebView.getSettings().setSupportMultipleWindows(true);
        mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        // Setting view port for NB
        if(viewPortWide){
            mWebView.getSettings().setUseWideViewPort(viewPortWide);
        }
        // Hiding the overlay
        View transOverlay = findViewById(R.id.trans_overlay);
        transOverlay.setVisibility(View.GONE);

        mWebView.addJavascriptInterface(new Object() {
            @JavascriptInterface
            public void onSuccess() {
                onSuccess("");
            }

            @JavascriptInterface
            public void onSuccess(final String result) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Intent intent = new Intent();
                        intent.putExtra("result", result);
                        setResult(RESULT_OK, intent);
                        finish();
                    }

                });
            }

            @JavascriptInterface
            public void onFailure() {
                onFailure("");
            }

            @JavascriptInterface
            public void onFailure(final String result) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Intent intent = new Intent();
                        intent.putExtra("result", result);
                        setResult(RESULT_CANCELED, intent);
                        finish();
                    }
                });
            }
        }, "PayU");

        mWebView.setWebChromeClient(new WebChromeClient() );
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setDomStorageEnabled(true);
        mWebView.postUrl(url, payuConfig.getData().getBytes());
         // add if using PayU SDK
         (new PayuUtils()).deviceAnalytics(PaymentsActivity.this, Bank.Version, merchantKey, txnId);
    }

    /*mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.getSettings().setDomStorageEnabled(true);
    // url = payuConfig.getEnvironment() == PayuConstants.PRODUCTION_ENV?  PayuConstants.PRODUCTION_PAYMENT_URL : PayuConstants.MOBILE_TEST_PAYMENT_URL ;
    mWebView.postUrl(url, EncodingUtils.getBytes(payuConfig.getData(), "base64"));*/

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_payments, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

@Override
public void onBackPressed(){
    if(cancelTransaction){
        cancelTransaction = false;
        Intent intent = new Intent();
        intent.putExtra("result", "Transaction canceled due to back pressed!");
        setResult(RESULT_CANCELED, intent);
        super.onBackPressed();
        return;
    }

    AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);;
    alertDialog.setCancelable(false);
    alertDialog.setMessage("Do you really want to cancel the transaction ?");
    alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            cancelTransaction = true;
            dialog.dismiss();
            onBackPressed();
        }
    });
    alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
    });
    alertDialog.show();
}

@Override
public void onDestroy(){
    super.onDestroy();

}
  1. Add following variable to class

    Bundle bundle; String url; boolean cancelTransaction = false; PayuConfig payuConfig; private BroadcastReceiver mReceiver = null; private String UTF = "UTF-8"; private boolean viewPortWide = false; private WebView mWebView;

  2. Proguard rules

         -keepclassmembers class com.payu.custombrowser.** {
          *;
          }
         -keepclassmembers class * {
        @android.webkit.JavascriptInterface <methods>;
         }
        -keepattributes Signature
        -keepattributes *Annotation*
        -keepattributes JavascriptInterface
        -keep public class com.payu.sdk.ProcessPaymentActivity$PayUJavaScriptInterface
        -keep public class * implements com.payu.sdk.ProcessPaymentActivity$PayUJavaScriptInterface