Camera permission on launch

User
Apache cordova when ever application launch please ask for camera permission if already not granted from user in android phone
Assistant
To ensure that your Apache Cordova application **always prompts for camera permission** on Android when the app launches (if not already granted), follow these steps:

### ✅ 1. **Install the Camera Plugin**
Make sure you have the `cordova-plugin-camera` installed:

cordova plugin add cordova-plugin-camera

Also, for permissions:

cordova plugin add cordova-plugin-android-permissions

### ✅ 2. **Request Camera Permission on App Launch**

Add this code inside your `deviceready` event in `index.js` or similar file:

document.addEventListener('deviceready', function () {
    var permissions = cordova.plugins.permissions;

    permissions.checkPermission(permissions.CAMERA, function (status) {
        if (!status.hasPermission) {
            permissions.requestPermission(permissions.CAMERA, function (status) {
                if (!status.hasPermission) {
                    alert("Camera permission is required to use this app.");
                }
            }, function () {
                alert("Camera permission request denied.");
            });
        }
    }, function () {
        alert("Failed to check camera permission.");
    });
});

### ✅ 3. **Ensure Camera Permission in `AndroidManifest.xml`**

Cordova usually adds this automatically, but to double-check, make sure your `config.xml` includes:

<platform name="android">
    <edit-config file="AndroidManifest.xml" mode="merge" target="uses-permission">
        <uses-permission android:name="android.permission.CAMERA" />
    </edit-config>
</platform>

Or manually verify `AndroidManifest.xml` has:

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

### ✅ 4. **Build and Test**

Rebuild your app to reflect changes:

cordova build android

Then install and test on a device where camera permission is **not yet granted**.

Let me know if you also want it to **prompt again if the user previously denied it** (which may require redirecting to app settings).

User
document.addEventListener('deviceready', function () {
var permissions = cordova.plugins.permissions;

permissions.checkPermission(permissions.CAMERA, function (status) {
if (!status.hasPermission) {
permissions.requestPermission(permissions.CAMERA, function (status) {
if (!status.hasPermission) {
alert("Camera permission is required to use this app.");
}
}, function () {
alert("Camera permission request denied.");
});
}
}, function () {
alert("Failed to check camera permission.");
});
})
Is above is required

Assistant
Yes, **the code you posted is required** if you want your Apache Cordova app to **explicitly check and request camera permission at launch** on Android.

Let’s break it down:

### ✅ Why This Is Required

On **Android 6.0+ (API 23+)**, **runtime permissions** are mandatory for dangerous permissions like `CAMERA`. Cordova plugins (like the Camera plugin) **do not request permissions automatically** on app launch—you must do it manually if needed.

Your code ensures:

– ✅ Checks if camera permission is already granted.
– ✅ If not, it **asks the user for permission**.
– ❌ If denied, it shows an alert.

### 🔒 Without This Code

If you **only use `cordova-plugin-camera`**, it will **ask for permission only when you try to open the camera**. If your app needs to **ask up front at launch**, you must keep this code.

### ✅ Final Answer

Yes, **keep this code** if you want the app to:

– Prompt for **camera access at launch**
– Avoid crashing or failing later when the camera is needed

Let me know if you also want to **redirect to app settings** if permission is permanently denied.

User
document.addEventListener('deviceready', function()
{
var TOKEN = 'fossettscircustoken';

$(document).ready(function()
{
var eventId = -1;
var eventDateId = -1;
let ApiUrl = 'https://staging.fossettscircus.com/boxoffice/index.php/api/';
let loader=`
Loading…
`;
var scanConfig = {
preferFrontCamera : false, // iOS and Android
showFlipCameraButton : true, // iOS and Android
showTorchButton : true, // iOS and Android
torchOn: false, // Android, launch with the torch switched on (if available)
saveHistory: false, // Android, save scan history (default false)
prompt : "Place a code inside the scan area", // Android
resultDisplayDuration: 500, // Android, display scanned text for X ms. 0 suppresses it entirely, default 1500
formats : "QR_CODE", // default: all but PDF_417 and RSS_EXPANDED
//orientation : "landscape", // Android only (portrait|landscape), default unset so it rotates with the device
disableAnimations : true, // iOS
disableSuccessBeep: false // iOS and Android
};

var sendCode = function(code)
{
$('.scan').prop('disabled', true);
$('.manually').prop('disabled', true);
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Code '+ code +' sent to boxoffice, plase wait…');

$.ajax({
url: `${ApiUrl}scan`,
method: 'POST',
data: {
token: TOKEN,
event_date_id: eventDateId,
order_code: code
},
success: function(result,status,xhr)
{
var apiResult = JSON.parse(result);

if ( apiResult.result )
{
$('#scan-result').removeClass('bg-dark').addClass('bg-success').html(apiResult.message+''+apiResult.seating+''+apiResult.tickets);

// reset input to set next code
$('[name="code"]').val(eventId +'.'+ eventDateId +'.');
}
else
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html(apiResult.message);
}
},
error: function(xhr,status,error)
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Code '+ result.text +' could not be sent to boxoffice, please try again');
},
complete: function()
{
$('.scan').prop('disabled', false);
$('.manually').prop('disabled', false);
}
});
}

var scanError = function (error)
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html("Scanning failed: " + error);

$('#modal-scan-result').modal('show');
};

var scanSuccess = function(result)
{
if (! result.cancelled )
{
if (eventDateId > -1)
{
sendCode(result.text);
}
else
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html('You must select an event date to scan tickets');
}
}
else
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Scan was cancelled');
}

$('#modal-scan-result').modal('show');
};

$(document).on('click', '.reload-events', function()
{
$('ul.events').html(loader);

$.ajax({
url: `${ApiUrl}today`,
method: 'POST',
data: {
token: TOKEN
},
success: function(result,status,xhr)
{
console.log(result);
var events = JSON.parse(result);
if (events.result) {
$('ul.events').html('');

$.each(events.data, function(i, val)
{
var eventDatetime = new Date(val.event_datetime);
var dateOptions = { year: '2-digit', month: '2-digit', day: '2-digit' };
var timeOptions = { hour12: true, hour: '2-digit', minute: '2-digit' };

$('.events').append(''+eventDatetime.toLocaleDateString('en-GB', dateOptions)+' – '+ eventDatetime.toLocaleTimeString('en-US', timeOptions) +' Wednesday – '+ val.venue_full +'');
});
}else{
$('.events').html(`${events.message}`);
}
},
error: function(xhr,status,error)
{
console.log(error);
}
});
});

// load events click
$('.reload-events').trigger('click');

$(document).on('click', '.events .list-group-item', function()
{
$('.events .list-group-item').removeClass('active');
$(this).addClass('active');

$('#scan-info').html($(this).html());

eventId = $(this).attr('data-event-id');
eventDateId = $(this).attr('data-event-date-id');

$('[name="code"]').val(eventId +'.'+ eventDateId +'.');

// first scan on event date click
//cordova.plugins.barcodeScanner.scan(scanSuccess, scanError, scanConfig);
$('#modal-scan-result').modal('show');
});

$(document).on('click', '.scan', function()
{
cordova.plugins.barcodeScanner.scan(scanSuccess, scanError, scanConfig);
});

$(document).on('click', '.manually', function()
{
sendCode($('[name="code"]').val());
});
});

}, false);

How to adjust above we have also browser platform for cordova

Assistant
To **adjust your Cordova app script to handle camera permission dynamically** and **support both Android and browser platforms** safely, you need to:

## ✅ 1. Add Camera Permission Check (Android Only)
You should **only check/request camera permission** if the app is running on Android, because:

– `cordova.plugins.permissions` is Android-specific
– It will **fail in the browser** or throw errors on iOS if not guarded

## ✅ 2. Wrap Your Permission Code with Platform Check

Update your `deviceready` block like this (at the **top inside `deviceready`**):

document.addEventListener('deviceready', function () {
    // Only run on Android platform
    if (cordova.platformId === 'android') {
        var permissions = cordova.plugins.permissions;

        permissions.checkPermission(permissions.CAMERA, function (status) {
            if (!status.hasPermission) {
                permissions.requestPermission(permissions.CAMERA, function (status) {
                    if (!status.hasPermission) {
                        alert("Camera permission is required to scan QR codes.");
                    }
                }, function () {
                    alert("Camera permission request denied.");
                });
            }
        }, function () {
            alert("Failed to check camera permission.");
        });
    }

    // The rest of your existing jQuery logic starts here
    $(document).ready(function () {
        // your full code goes here...
    });

}, false);

## ✅ 3. Prevent `cordova.plugins.barcodeScanner` from running on Browser

Wrap scanner logic like this:

$(document).on('click', '.scan', function () {
    if (cordova.platformId === 'browser') {
        alert('QR scanning is not supported in browser.');
    } else {
        cordova.plugins.barcodeScanner.scan(scanSuccess, scanError, scanConfig);
    }
});

## ✅ Summary of What Was Added

| ✅ Change | 💡 Purpose |
|———-|————|
| `cordova.platformId === 'android'` check | Prevents camera permission logic from crashing on unsupported platforms |
| `cordova.platformId === 'browser'` in `.scan` click | Graceful fallback if user tries to scan in browser |
| Wrapped `cordova.plugins.permissions` code | Avoids breaking app in browser or iOS |

Let me know if you want to also add fallback for iOS permissions (they work differently) or simulate barcode scanning in browser for testing.

User
I don't want custom alert for permission, I want default alert from andrid phone
Assistant
Perfect — if you **don't want to show custom `alert()` messages**, and instead want **Android’s default permission popup** to appear, you only need to:

### ✅ Just Request the Permission, No Alerts

Update the `deviceready` block like this:

document.addEventListener('deviceready', function () {
    if (cordova.platformId === 'android') {
        var permissions = cordova.plugins.permissions;

        permissions.checkPermission(permissions.CAMERA, function (status) {
            if (!status.hasPermission) {
                permissions.requestPermission(
                    permissions.CAMERA,
                    function (status) {
                        // Permission granted or not — don't alert, Android will handle it
                    },
                    function () {
                        // No need to alert
                    }
                );
            }
        });
    }

    $(document).ready(function () {
        // your full code here...
    });

}, false);

### ✅ Why This Works

– If the user **hasn't granted** the permission, Android will show the **default system permission dialog** (with **Allow** / **Deny**).
– If already granted, nothing happens — your app continues silently.
– No `alert()` or custom dialog will interrupt the flow.

Let me know if you want to **prompt again** if the user permanently denied permission (which requires going to **app settings**, because Android won’t show the popup again after "Don't ask again").

User
onlyshow splashscreen without permission and if deny permission then close app
Assistant
To meet your goal:

– ✅ **Show only splash screen on launch**
– ✅ **Ask for camera permission after splash**
– ❌ **If user denies camera permission**, automatically **close the app**

### ✅ Step-by-Step Implementation

#### 1. **Keep the splash screen until permission is resolved**

Make sure you're using the splash screen plugin:

cordova plugin add cordova-plugin-splashscreen

Then add to `config.xml`:

<preference name="SplashScreenDelay" value="10000" /> <!-- delay in ms -->
<preference name="FadeSplashScreenDuration" value="500" />
<preference name="AutoHideSplashScreen" value="false" />

> This disables auto-hide. We'll hide it manually after checking permission.

#### 2. **Request camera permission after deviceready**

Update your `index.js` or equivalent script:

document.addEventListener('deviceready', function () {
    if (cordova.platformId === 'android') {
        var permissions = cordova.plugins.permissions;

        permissions.checkPermission(permissions.CAMERA, function (status) {
            if (!status.hasPermission) {
                // Request permission
                permissions.requestPermission(permissions.CAMERA, function (status) {
                    if (status.hasPermission) {
                        navigator.splashscreen.hide(); // Hide splash if granted
                    } else {
                        navigator.app.exitApp(); // Close app if denied
                    }
                }, function () {
                    navigator.app.exitApp(); // Close app if error or denied
                });
            } else {
                navigator.splashscreen.hide(); // Already granted
            }
        });
    } else {
        navigator.splashscreen.hide(); // iOS or browser fallback
    }
}, false);

### ✅ Plugin Requirements

Ensure these plugins are installed:

cordova plugin add cordova-plugin-android-permissions
cordova plugin add cordova-plugin-splashscreen
cordova plugin add cordova-plugin-globalization
cordova plugin add cordova-plugin-dialogs

(`cordova-plugin-dialogs` is optional unless you want native confirms)

### ✅ Summary

| ✅ Action | 💡 Result |
|———-|———–|
| `AutoHideSplashScreen = false` | Keeps splash until permission handled |
| Check/request `CAMERA` permission | Android default dialog appears |
| If granted | Hide splash and continue app |
| If denied | Exit app using `navigator.app.exitApp()` |

Let me know if you want to show a confirmation before exit or handle other permissions like storage too.

User
document.addEventListener('deviceready', function()
{
// Only run on Android platform
if (cordova.platformId === 'android') {
var permissions = cordova.plugins.permissions;

permissions.checkPermission(permissions.CAMERA, function (status) {
if (!status.hasPermission) {
permissions.requestPermission(
permissions.CAMERA,
function (status) {
// Permission granted or not — don't alert, Android will handle it
},
function () {
// No need to alert
}
);
}
});
}
let TOKEN = 'fossettscircustoken';

$(document).ready(function()
{
var eventId = -1;
var eventDateId = -1;
let ApiUrl = 'https://staging.fossettscircus.com/boxoffice/index.php/api/';
let loader=`
Loading…
`;
var scanConfig = {
preferFrontCamera : false, // iOS and Android
showFlipCameraButton : true, // iOS and Android
showTorchButton : true, // iOS and Android
torchOn: false, // Android, launch with the torch switched on (if available)
saveHistory: false, // Android, save scan history (default false)
prompt : "Place a code inside the scan area", // Android
resultDisplayDuration: 500, // Android, display scanned text for X ms. 0 suppresses it entirely, default 1500
formats : "QR_CODE", // default: all but PDF_417 and RSS_EXPANDED
//orientation : "landscape", // Android only (portrait|landscape), default unset so it rotates with the device
disableAnimations : true, // iOS
disableSuccessBeep: false // iOS and Android
};

var sendCode = function(code)
{
$('.scan').prop('disabled', true);
$('.manually').prop('disabled', true);
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Code '+ code +' sent to boxoffice, plase wait…');

$.ajax({
url: `${ApiUrl}scan`,
method: 'POST',
data: {
token: TOKEN,
event_date_id: eventDateId,
order_code: code
},
success: function(result,status,xhr)
{
var apiResult = JSON.parse(result);

if ( apiResult.result )
{
$('#scan-result').removeClass('bg-dark').addClass('bg-success').html(apiResult.message+''+apiResult.seating+''+apiResult.tickets);

// reset input to set next code
$('[name="code"]').val(eventId +'.'+ eventDateId +'.');
}
else
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html(apiResult.message);
}
},
error: function(xhr,status,error)
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Code '+ result.text +' could not be sent to boxoffice, please try again');
},
complete: function()
{
$('.scan').prop('disabled', false);
$('.manually').prop('disabled', false);
}
});
}

var scanError = function (error)
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html("Scanning failed: " + error);

$('#modal-scan-result').modal('show');
};

var scanSuccess = function(result)
{
if (! result.cancelled )
{
if (eventDateId > -1)
{
sendCode(result.text);
}
else
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html('You must select an event date to scan tickets');
}
}
else
{
$('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Scan was cancelled');
}

$('#modal-scan-result').modal('show');
};

$(document).on('click', '.reload-events', function()
{
$('ul.events').html(loader);

$.ajax({
url: `${ApiUrl}today`,
method: 'POST',
data: {
token: TOKEN
},
success: function(result,status,xhr)
{
console.log(result);
var events = JSON.parse(result);
if (events.result) {
$('ul.events').html('');

$.each(events.data, function(i, val)
{
var eventDatetime = new Date(val.event_datetime);
var dateOptions = { year: '2-digit', month: '2-digit', day: '2-digit' };
var timeOptions = { hour12: true, hour: '2-digit', minute: '2-digit' };

$('.events').append(''+eventDatetime.toLocaleDateString('en-GB', dateOptions)+' – '+ eventDatetime.toLocaleTimeString('en-US', timeOptions) +' Wednesday – '+ val.venue_full +'');
});
}else{
$('.events').html(`${events.message}`);
}
},
error: function(xhr,status,error)
{
console.log(error);
}
});
});

// load events click
$('.reload-events').trigger('click');

$(document).on('click', '.events .list-group-item', function()
{
$('.events .list-group-item').removeClass('active');
$(this).addClass('active');

$('#scan-info').html($(this).html());

eventId = $(this).attr('data-event-id');
eventDateId = $(this).attr('data-event-date-id');

$('[name="code"]').val(eventId +'.'+ eventDateId +'.');

// first scan on event date click
//cordova.plugins.barcodeScanner.scan(scanSuccess, scanError, scanConfig);
$('#modal-scan-result').modal('show');
});

$(document).on('click', '.scan', function()
{
cordova.plugins.barcodeScanner.scan(scanSuccess, scanError, scanConfig);
});

$(document).on('click', '.manually', function()
{
sendCode($('[name="code"]').val());
});
});

}, false);

How to adjust this code

Assistant
To adjust **your full code** so that:

1. ✅ The splash screen shows on app launch
2. ✅ Camera permission is requested **before anything else happens**
3. ❌ If the permission is denied, the app **closes immediately**
4. ✅ The rest of your logic (like `.reload-events`, scanning, etc.) only runs **after** camera permission is granted

### ✅ **Full Adjusted Code (Cleaned + Functional)**

Here’s your updated code with comments and permission logic placed correctly:

document.addEventListener('deviceready', function () {
    if (cordova.platformId === 'android') {
        var permissions = cordova.plugins.permissions;

        permissions.checkPermission(permissions.CAMERA, function (status) {
            if (!status.hasPermission) {
                // Request permission
                permissions.requestPermission(
                    permissions.CAMERA,
                    function (status) {
                        if (status.hasPermission) {
                            navigator.splashscreen.hide(); // Hide splash after permission
                            initializeApp(); // Proceed with your app
                        } else {
                            navigator.app.exitApp(); // Exit if denied
                        }
                    },
                    function () {
                        navigator.app.exitApp(); // Exit on request error
                    }
                );
            } else {
                navigator.splashscreen.hide();
                initializeApp(); // Permission already granted
            }
        });
    } else {
        navigator.splashscreen.hide(); // For browser/iOS fallback
        initializeApp();
    }
}, false);

### 🔁 Wrap your jQuery app logic inside a new function `initializeApp()`

function initializeApp() {
    let TOKEN = 'fossettscircustoken';
    let eventId = -1;
    let eventDateId = -1;
    let ApiUrl = 'https://staging.fossettscircus.com/boxoffice/index.php/api/';
    let loader = `<li class="text-center"><div class="spinner-border text-primary" role="status">
                    <span class="sr-only">Loading...</span>
                  </div></li>`;
    let scanConfig = {
        preferFrontCamera: false,
        showFlipCameraButton: true,
        showTorchButton: true,
        torchOn: false,
        saveHistory: false,
        prompt: "Place a code inside the scan area",
        resultDisplayDuration: 500,
        formats: "QR_CODE",
        disableAnimations: true,
        disableSuccessBeep: false
    };

    $(document).ready(function () {

        var sendCode = function (code) {
            $('.scan').prop('disabled', true);
            $('.manually').prop('disabled', true);
            $('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Code <u class="bg-primary text-white p-1">' + code + '</u> sent to boxoffice, please wait...');

            $.ajax({
                url: `${ApiUrl}scan`,
                method: 'POST',
                data: {
                    token: TOKEN,
                    event_date_id: eventDateId,
                    order_code: code
                },
                success: function (result, status, xhr) {
                    var apiResult = JSON.parse(result);

                    if (apiResult.result) {
                        $('#scan-result').removeClass('bg-dark').addClass('bg-success').html(apiResult.message + '<br>' + apiResult.seating + '<br>' + apiResult.tickets);
                        $('[name="code"]').val(eventId + '.' + eventDateId + '.');
                    } else {
                        $('#scan-result').removeClass('bg-success').addClass('bg-dark').html(apiResult.message);
                    }
                },
                error: function (xhr, status, error) {
                    $('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Code could not be sent to boxoffice, please try again');
                },
                complete: function () {
                    $('.scan').prop('disabled', false);
                    $('.manually').prop('disabled', false);
                }
            });
        };

        var scanError = function (error) {
            $('#scan-result').removeClass('bg-success').addClass('bg-dark').html("Scanning failed: " + error);
            $('#modal-scan-result').modal('show');
        };

        var scanSuccess = function (result) {
            if (!result.cancelled) {
                if (eventDateId > -1) {
                    sendCode(result.text);
                } else {
                    $('#scan-result').removeClass('bg-success').addClass('bg-dark').html('You must select an event date to scan tickets');
                }
            } else {
                $('#scan-result').removeClass('bg-success').addClass('bg-dark').html('Scan was cancelled');
            }
            $('#modal-scan-result').modal('show');
        };

        $(document).on('click', '.reload-events', function () {
            $('ul.events').html(loader);

            $.ajax({
                url: `${ApiUrl}today`,
                method: 'POST',
                data: { token: TOKEN },
                success: function (result, status, xhr) {
                    var events = JSON.parse(result);
                    if (events.result) {
                        $('ul.events').html('');
                        $.each(events.data, function (i, val) {
                            var eventDatetime = new Date(val.event_datetime);
                            var dateOptions = { year: '2-digit', month: '2-digit', day: '2-digit' };
                            var timeOptions = { hour12: true, hour: '2-digit', minute: '2-digit' };
                            $('.events').append('<li class="list-group-item text-center" data-event-id="' + val.event_id + '" data-event-date-id="' + val.event_date_id + '">' + eventDatetime.toLocaleDateString('en-GB', dateOptions) + ' - ' + eventDatetime.toLocaleTimeString('en-US', timeOptions) + ' Wednesday - ' + val.venue_full + '</li>');
                        });
                    } else {
                        $('.events').html(`<li class="no-result-item text-center bg-info text-white">${events.message}</li>`);
                    }
                },
                error: function (xhr, status, error) {
                    console.log(error);
                }
            });
        });

        $('.reload-events').trigger('click');

        $(document).on('click', '.events .list-group-item', function () {
            $('.events .list-group-item').removeClass('active');
            $(this).addClass('active');

            $('#scan-info').html($(this).html());

            eventId = $(this).attr('data-event-id');
            eventDateId = $(this).attr('data-event-date-id');

            $('[name="code"]').val(eventId + '.' + eventDateId + '.');

            $('#modal-scan-result').modal('show');
        });

        $(document).on('click', '.scan', function () {
            cordova.plugins.barcodeScanner.scan(scanSuccess, scanError, scanConfig);
        });

        $(document).on('click', '.manually', function () {
            sendCode($('[name="code"]').val());
        });

    }); // end of jQuery ready
}

### ✅ Plugins You Need

Ensure these plugins are added:

cordova plugin add cordova-plugin-splashscreen
cordova plugin add cordova-plugin-android-permissions
cordova plugin add phonegap-plugin-barcodescanner

### ✅ Result:

– 📱 Splash screen stays visible.
– 🛑 App won't proceed unless camera permission is granted.
– ❌ If denied, app exits.
– ✅ Your full logic executes only after permission is granted.

Let me know if you want to auto-redirect to **app settings** if the user selects "Don't ask again."

Leave a Comment

Your email address will not be published. Required fields are marked *