Skip to content
This repository has been archived by the owner on Oct 10, 2024. It is now read-only.

Commit

Permalink
✨ feat: add support for capacitor v3 (#44)
Browse files Browse the repository at this point in the history
* ⬆️ upgrade capacitor packages

* ♻️ [android] refactor code to support new way of handling permissions

* ♻️ [ios] refactor code to support v3

* ♻️ [web] refactor code to support v3

* 🔨 refactor package and rollup to reflect new v3 defaults

* 📝 update documentation

* 🔖 v2.0.0-alpha.0

* 🔨 refactor package and rollup to reflect new v3 defaults

* ♻️ [web] refactor error throwing to reflect new capacitor preferences

* 📝 update documentation to reflex new capacitor preferences

* 🐛 fix typescript definitions

* 🔖 v2.0.0-alpha.1
  • Loading branch information
tafelnl authored Jun 4, 2021
1 parent 03f9400 commit d5acea7
Show file tree
Hide file tree
Showing 14 changed files with 1,614 additions and 2,411 deletions.
2 changes: 1 addition & 1 deletion CapacitorCommunityBarcodeScanner.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Pod::Spec.new do |s|
s.author = package['author']
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
s.ios.deployment_target = '11.0'
s.ios.deployment_target = '12.0'
s.dependency 'Capacitor'
s.swift_version = '5.1'
end
67 changes: 13 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
- [Maintainers](#maintainers)
- [About](#about)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Troubleshooting](#troubleshooting)

Expand All @@ -49,41 +48,6 @@ npx cap sync

### iOS

On iOS, no further steps are needed.

### Android

On Android, register the plugin in your main activity:

```java
import com.dutchconcepts.capacitor.barcodescanner.BarcodeScanner;

public class MainActivity extends BridgeActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Initializes the Bridge
this.init(
savedInstanceState,
new ArrayList<Class<? extends Plugin>>() {
{
// Additional plugins you've installed go here
// Ex: add(TotallyAwesomePlugin.class);
add(BarcodeScanner.class);
}
}
);
}
}

```

## Configuration

### iOS

For iOS you need to set a usage description in your info.plist file.

This can be done by either adding it to the Source Code directly or by using Xcode Property List inspector.
Expand Down Expand Up @@ -140,11 +104,9 @@ Within your `AndroidManifest.xml` file, change the following:
Scanning a (QR) barcode can be as simple as:

```js
import { Plugins } from '@capacitor/core';
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';

const startScan = async () => {
const { BarcodeScanner } = Plugins;

BarcodeScanner.hideBackground(); // make background of WebView transparent

const result = await BarcodeScanner.startScan(); // start scanning and wait for a result
Expand All @@ -160,7 +122,7 @@ const startScan = async () => {

Because of the fact that the Scanner View will be rendered behind the WebView, you will have to call `hideBackground()` to make the WebView and the `<html>` element transparent. Every other element that needs transparency, you will have to handle yourself.

The `<html>` element is made transparent by adding `background: 'transparent';` to the `style=""` attribute. So in theory it is possible that this is overwritten by some CSS property in your setup. Because this plugins does not aim to fix every single scenario out there, you will have to think of a workaround for this yourself, if this applies to you (probably not).
The `<html>` element is made transparent by adding `background: 'transparent';` to the `style=""` attribute. So in theory it is possible that this is overwritten by some CSS property in your setup. Because this plugin does not aim to fix every single scenario out there, you will have to think of a workaround for this yourself, if this applies to you (probably not).

If you still cannot see the camera view, check if any other elements are blocking it. For more info on this see [here](#the-scanner-view-does-not-show-up).

Expand All @@ -169,10 +131,9 @@ If you still cannot see the camera view, check if any other elements are blockin
After `startScan()` is resolved, the Scanner View will be automatically destroyed to save battery. But if you want to cancel the scan before `startScan()` is resolved (AKA no code has been recognized yet), you will have to call `stopScan()` manually. Example:

```js
import { Plugins } from '@capacitor/core';
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';

const stopScan = () => {
const { BarcodeScanner } = Plugins;
BarcodeScanner.showBackground();
BarcodeScanner.stopScan();
};
Expand All @@ -184,12 +145,11 @@ In Vue.js you could do something like this in a specific view where you use the

```vue
<script>
import { Plugins } from '@capacitor/core';
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';
export default {
methods: {
stopScan() {
const { BarcodeScanner } = Plugins;
BarcodeScanner.showBackground();
BarcodeScanner.stopScan();
},
Expand All @@ -213,15 +173,13 @@ To boost performance and responsiveness (by just a bit), a `prepare()` method is
For example:

```js
import { Plugins } from '@capacitor/core';
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';

const prepare = () => {
const { BarcodeScanner } = Plugins;
BarcodeScanner.prepare();
};

const startScan = async () => {
const { BarcodeScanner } = Plugins;
BarcodeScanner.hideBackground();
const result = await BarcodeScanner.startScan();
if (result.hasContent) {
Expand All @@ -230,7 +188,6 @@ const startScan = async () => {
};

const stopScan = () => {
const { BarcodeScanner } = Plugins;
BarcodeScanner.showBackground();
BarcodeScanner.stopScan();
};
Expand All @@ -253,8 +210,9 @@ askUser();
This is fully optional and would work the same as:

```js
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';

const startScan = async () => {
const { BarcodeScanner } = Plugins;
BarcodeScanner.hideBackground();
const result = await BarcodeScanner.startScan();
if (result.hasContent) {
Expand All @@ -280,9 +238,9 @@ The latter will just appear a little slower to the user.
This plugin does not automatically handle permissions. But the plugin _does_ have a utility method to check and request the permission. You will have to request the permission from JavaScript. A simple example follows:

```js
const checkPermission = async () => {
const { BarcodeScanner } = Plugins;
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';

const checkPermission = async () => {
// check or request permission
const status = await BarcodeScanner.checkPermission({ force: true });

Expand All @@ -298,8 +256,9 @@ const checkPermission = async () => {
A more detailed and more UX-optimized example:

```js
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';

const didUserGrantPermission = async () => {
const { BarcodeScanner } = Plugins;
// check if user already granted permission
const status = await BarcodeScanner.checkPermission({ force: false });

Expand Down Expand Up @@ -361,9 +320,9 @@ didUserGrantPermission();
If a user denied the permission for good, `status.denied` will be set to true. On Android this will happen only when the user checks the box `never ask again`. To get the permission anyway you will have to redirect the user to the settings of the app. This can be done simply be doing the following:

```js
const checkPermission = async () => {
const { BarcodeScanner } = Plugins;
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';

const checkPermission = async () => {
const status = await BarcodeScanner.checkPermission();

if (status.denied) {
Expand Down
6 changes: 4 additions & 2 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package="com.dutchconcepts.capacitor.barcodescanner"
android:hardwareAccelerated="true">

<uses-feature android:name="android.hardware.camera"
android:required="false" />
<!-- Paste the following line into the AndroidManifest.xml of your project -->
<!-- See also: https://capacitorjs.com/docs/plugins/android#manifest -->
<!-- <uses-feature android:name="android.hardware.camera" android:required="false" /> -->

<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
import android.widget.FrameLayout;
import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.NativePlugin;
import com.getcapacitor.PermissionState;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.annotation.Permission;
import com.getcapacitor.annotation.PermissionCallback;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.ResultPoint;
import com.journeyapps.barcodescanner.BarcodeCallback;
Expand All @@ -34,9 +37,11 @@
import java.util.Map;
import org.json.JSONException;

@NativePlugin(permissionRequestCode = BarcodeScanner.REQUEST_CODE)
@CapacitorPlugin(permissions = { @Permission(strings = { Manifest.permission.CAMERA }, alias = BarcodeScanner.PERMISSION_ALIAS_CAMERA) })
public class BarcodeScanner extends Plugin implements BarcodeCallback {

public static final String PERMISSION_ALIAS_CAMERA = "camera";

private BarcodeView mBarcodeView;

private int currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
Expand Down Expand Up @@ -325,8 +330,6 @@ public void stopScan(PluginCall call) {
call.resolve();
}

static final int REQUEST_CODE = 57351;

private static final String TAG_PERMISSION = "permission";

private static final String GRANTED = "granted";
Expand All @@ -336,13 +339,12 @@ public void stopScan(PluginCall call) {

private static final String PERMISSION_NAME = Manifest.permission.CAMERA;

private PluginCall savedCall;
private JSObject savedReturnObject;

void _checkPermission(PluginCall call, boolean force) {
this.savedReturnObject = new JSObject();

if (hasPermission(PERMISSION_NAME)) {
if (getPermissionState(PERMISSION_ALIAS_CAMERA) == PermissionState.GRANTED) {
// permission GRANTED
this.savedReturnObject.put(GRANTED, true);
} else {
Expand All @@ -367,10 +369,8 @@ void _checkPermission(PluginCall call, boolean force) {
// can be asked (again)
if (force) {
// request permission
// also set this.savedCall = call
// so a callback can be made from the handleRequestPermissionsResult
pluginRequestPermission(PERMISSION_NAME, REQUEST_CODE);
this.savedCall = call;
requestPermissionForAlias(PERMISSION_ALIAS_CAMERA, call, "cameraPermsCallback");
return;
}
} else {
Expand All @@ -389,7 +389,7 @@ void _checkPermission(PluginCall call, boolean force) {
call.resolve(this.savedReturnObject);
}

private static String PREFS_PERMISSION_FIRST_TIME_ASKING = "PREFS_PERMISSION_FIRST_TIME_ASKING";
private static final String PREFS_PERMISSION_FIRST_TIME_ASKING = "PREFS_PERMISSION_FIRST_TIME_ASKING";

private void setPermissionFirstTimeAsking(String permission, boolean isFirstTime) {
SharedPreferences sharedPreference = getActivity().getSharedPreferences(PREFS_PERMISSION_FIRST_TIME_ASKING, MODE_PRIVATE);
Expand All @@ -400,22 +400,19 @@ private boolean isPermissionFirstTimeAsking(String permission) {
return getActivity().getSharedPreferences(PREFS_PERMISSION_FIRST_TIME_ASKING, MODE_PRIVATE).getBoolean(permission, true);
}

@Override
protected void handleRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.handleRequestPermissionsResult(requestCode, permissions, grantResults);

if (this.savedCall == null || this.savedReturnObject == null || permissions.length <= 0) {
@PermissionCallback
private void cameraPermsCallback(PluginCall call) {
if (this.savedReturnObject == null) {
// No stored plugin call for permissions request result
return;
}
String permission = permissions[0];

// the user was apparently requested this permission
// update the preferences to reflect this
setPermissionFirstTimeAsking(permission, false);
setPermissionFirstTimeAsking(PERMISSION_NAME, false);

boolean granted = false;
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (getPermissionState(PERMISSION_ALIAS_CAMERA) == PermissionState.GRANTED) {
granted = true;
}

Expand All @@ -428,7 +425,7 @@ protected void handleRequestPermissionsResult(int requestCode, String[] permissi
this.savedReturnObject.put(GRANTED, true);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (getActivity().shouldShowRequestPermissionRationale(permission)) {
if (getActivity().shouldShowRequestPermissionRationale(PERMISSION_NAME)) {
// permission DENIED
// BUT not for always
Log.d(TAG_PERMISSION, "Asked. Denied For Now");
Expand All @@ -448,9 +445,8 @@ protected void handleRequestPermissionsResult(int requestCode, String[] permissi
}
}
// resolve saved call
this.savedCall.resolve(this.savedReturnObject);
call.resolve(this.savedReturnObject);
// release saved vars
this.savedCall = null;
this.savedReturnObject = null;
}

Expand All @@ -461,13 +457,11 @@ public void checkPermission(PluginCall call) {
_checkPermission(call, force);
}

private static final int RESULT_CODE = 8309;

@PluginMethod
public void openAppSettings(PluginCall call) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", getAppId(), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(call, intent, RESULT_CODE);
startActivityForResult(call, intent, "openSettingsResult");
call.resolve();
}
}
8 changes: 4 additions & 4 deletions ios/Plugin.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -425,7 +425,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
Expand All @@ -448,7 +448,7 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Plugin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)";
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin;
Expand All @@ -473,7 +473,7 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Plugin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)";
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin;
Expand Down
Loading

0 comments on commit d5acea7

Please sign in to comment.