Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix MissingPluginException for Android #163

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/libraries/Flutter_Plugins.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.content.pm.PackageManager;
import androidx.core.app.ActivityCompat;

import com.yalantis.ucrop.UCrop;
import com.yalantis.ucrop.model.AspectRatio;
Expand All @@ -20,7 +22,18 @@

import static android.app.Activity.RESULT_OK;

public class ImageCropperDelegate implements PluginRegistry.ActivityResultListener {
public class ImageCropperDelegate implements PluginRegistry.ActivityResultListener,
PluginRegistry.RequestPermissionsResultListener {

static final int REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY = 2342;
static final int REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA = 2343;
static final int REQUEST_EXTERNAL_IMAGE_STORAGE_PERMISSION = 2344;
static final int REQUEST_CAMERA_IMAGE_PERMISSION = 2345;
static final int REQUEST_CODE_CHOOSE_VIDEO_FROM_GALLERY = 2352;
static final int REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA = 2353;
static final int REQUEST_EXTERNAL_VIDEO_STORAGE_PERMISSION = 2354;
static final int REQUEST_CAMERA_VIDEO_PERMISSION = 2355;

private final Activity activity;
private MethodChannel.Result pendingResult;
private FileUtils fileUtils;
Expand Down Expand Up @@ -127,6 +140,7 @@ private UCrop.Options setupUiCustomizedOptions(UCrop.Options options, MethodCall
Integer toolbarWidgetColor = call.argument("android.toolbar_widget_color");
Integer backgroundColor = call.argument("android.background_color");
Integer activeControlsWidgetColor = call.argument("android.active_controls_widget_color");
Integer activeWidgetColor = call.argument("android.active_widget_color");
Integer dimmedLayerColor = call.argument("android.dimmed_layer_color");
Integer cropFrameColor = call.argument("android.crop_frame_color");
Integer cropGridColor = call.argument("android.crop_grid_color");
Expand Down Expand Up @@ -158,6 +172,9 @@ private UCrop.Options setupUiCustomizedOptions(UCrop.Options options, MethodCall
if (activeControlsWidgetColor != null) {
options.setActiveControlsWidgetColor(activeControlsWidgetColor);
}
if (activeWidgetColor != null) {
//options.setActiveWidgetColor(activeWidgetColor);
}
if (dimmedLayerColor != null) {
options.setDimmedLayerColor(dimmedLayerColor);
}
Expand Down Expand Up @@ -227,4 +244,44 @@ private AspectRatio parseAspectRatioName(String name) {
CropImageView.SOURCE_IMAGE_ASPECT_RATIO, 1.0f);
}
}
}

@Override
public boolean onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
boolean permissionGranted =
grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;

switch (requestCode) {
case REQUEST_EXTERNAL_IMAGE_STORAGE_PERMISSION:
if (permissionGranted) {
}
break;
case REQUEST_EXTERNAL_VIDEO_STORAGE_PERMISSION:
if (permissionGranted) {
}
break;
case REQUEST_CAMERA_IMAGE_PERMISSION:
if (permissionGranted) {
}
break;
case REQUEST_CAMERA_VIDEO_PERMISSION:
if (permissionGranted) {
}
break;
default:
return false;
}

if (!permissionGranted) {
switch (requestCode) {
case REQUEST_EXTERNAL_IMAGE_STORAGE_PERMISSION:
case REQUEST_EXTERNAL_VIDEO_STORAGE_PERMISSION:
case REQUEST_CAMERA_IMAGE_PERMISSION:
case REQUEST_CAMERA_VIDEO_PERMISSION:
break;
}
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package vn.hunghd.flutter.plugins.imagecropper;

import android.util.Log;
import android.app.Activity;

import android.app.Application;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
Expand All @@ -17,29 +30,106 @@

/** ImageCropperPlugin */
public class ImageCropperPlugin implements MethodCallHandler, FlutterPlugin, ActivityAware {

private class LifeCycleObserver
implements Application.ActivityLifecycleCallbacks, DefaultLifecycleObserver {
private final Activity thisActivity;

LifeCycleObserver(Activity activity) {
this.thisActivity = activity;
}

@Override
public void onCreate(@NonNull LifecycleOwner owner) {}

@Override
public void onStart(@NonNull LifecycleOwner owner) {}

@Override
public void onResume(@NonNull LifecycleOwner owner) {}

@Override
public void onPause(@NonNull LifecycleOwner owner) {}

@Override
public void onStop(@NonNull LifecycleOwner owner) {
onActivityStopped(thisActivity);
}

@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
onActivityDestroyed(thisActivity);
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}

@Override
public void onActivityStarted(Activity activity) {}

@Override
public void onActivityResumed(Activity activity) {}

@Override
public void onActivityPaused(Activity activity) {}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}

@Override
public void onActivityDestroyed(Activity activity) {
if (thisActivity == activity && activity.getApplicationContext() != null) {
((Application) activity.getApplicationContext())
.unregisterActivityLifecycleCallbacks(
this); // Use getApplicationContext() to avoid casting failures
}
}

@Override
public void onActivityStopped(Activity activity) {
if (thisActivity == activity) {
//delegate.saveStateBeforeResult();
}
}
}

static
{
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
private static final String CHANNEL = "plugins.hunghd.vn/image_cropper";

private static ImageCropperPlugin instance;
private static MethodChannel channel;
private static ImageCropperDelegate delegate;
private static final String CHANNEL = "plugins.hunghd.vn/image_cropper";

// private static ImageCropperPlugin instance;
// private static MethodChannel channel;
// private static ImageCropperDelegate delegate;
// private ActivityPluginBinding activityBinding;
// private Activity activity;

private MethodChannel channel;
private ImageCropperDelegate delegate;
private FlutterPluginBinding pluginBinding;
private ActivityPluginBinding activityBinding;
private Application application;
private Activity activity;
// This is null when not using v2 embedding;
private Lifecycle lifecycle;
private LifeCycleObserver observer;

private final Object initializationLock = new Object();

/** Plugin registration. */
public static void registerWith(Registrar registrar) {
if (instance == null) {
instance = new ImageCropperPlugin();
if (registrar.activity() == null) {
return;
}
if (registrar.activity() != null) {
instance.onAttachedToEngine(registrar.messenger());
instance.onAttachedToActivity(registrar.activity());
registrar.addActivityResultListener(instance.getActivityResultListener());
Activity activity = registrar.activity();
Application application = null;
if (registrar.context() != null) {
application = (Application) (registrar.context().getApplicationContext());
}
ImageCropperPlugin plugin = new ImageCropperPlugin();
plugin.setup(registrar.messenger(), application, activity, registrar, null);
}

@Override
Expand All @@ -53,65 +143,90 @@ public void onMethodCall(MethodCall call, Result result) {
}
}

private void onAttachedToEngine(BinaryMessenger messenger) {
synchronized (initializationLock) {
if (channel != null) {
return;
}
public ImageCropperPlugin() {}

channel = new MethodChannel(messenger, CHANNEL);
channel.setMethodCallHandler(this);
}
}

private void onAttachedToActivity(Activity activity) {
@VisibleForTesting
ImageCropperPlugin(final ImageCropperDelegate delegate, final Activity activity) {
this.delegate = delegate;
this.activity = activity;
delegate = new ImageCropperDelegate(activity);
}

private PluginRegistry.ActivityResultListener getActivityResultListener() {
return delegate;
}

@Override
public void onAttachedToEngine(FlutterPluginBinding binding) {
onAttachedToEngine(binding.getBinaryMessenger());
pluginBinding = binding;
}

@Override
public void onDetachedFromEngine(FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
channel = null;
pluginBinding = null;
}


@Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
if (getActivityResultListener() != null) {
binding.removeActivityResultListener(getActivityResultListener());
}
onAttachedToActivity(binding.getActivity());
binding.addActivityResultListener(getActivityResultListener());
activityBinding = binding;
setup(
pluginBinding.getBinaryMessenger(),
(Application) pluginBinding.getApplicationContext(),
activityBinding.getActivity(),
null,
activityBinding);
}

@Override
public void onDetachedFromActivity() {
tearDown();
}

@Override
public void onDetachedFromActivityForConfigChanges() {
activity = null;
delegate = null;
onDetachedFromActivity();
}

@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
if (getActivityResultListener() != null) {
binding.removeActivityResultListener(getActivityResultListener());
onAttachedToActivity(binding);
}

private void setup(
final BinaryMessenger messenger,
final Application application,
final Activity activity,
final PluginRegistry.Registrar registrar,
final ActivityPluginBinding activityBinding) {
this.activity = activity;
this.application = application;
this.delegate = constructDelegate(activity);
channel = new MethodChannel(messenger, CHANNEL);
channel.setMethodCallHandler(this);
observer = new LifeCycleObserver(activity);
if (registrar != null) {
// V1 embedding setup for activity listeners.
application.registerActivityLifecycleCallbacks(observer);
registrar.addActivityResultListener(delegate);
registrar.addRequestPermissionsResultListener(delegate);
} else {
// V2 embedding setup for activity listeners.
activityBinding.addActivityResultListener(delegate);
activityBinding.addRequestPermissionsResultListener(delegate);
lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(activityBinding);
lifecycle.addObserver(observer);
}
onAttachedToActivity(binding.getActivity());
binding.addActivityResultListener(getActivityResultListener());
}

@Override
public void onDetachedFromActivity() {
activity = null;
private void tearDown() {
activityBinding.removeActivityResultListener(delegate);
activityBinding.removeRequestPermissionsResultListener(delegate);
activityBinding = null;
lifecycle.removeObserver(observer);
lifecycle = null;
delegate = null;
channel.setMethodCallHandler(null);
channel = null;
application.unregisterActivityLifecycleCallbacks(observer);
application = null;
}

private final ImageCropperDelegate constructDelegate(final Activity setupActivity) {
return new ImageCropperDelegate(setupActivity);
}
}
}
1 change: 1 addition & 0 deletions example/.flutter-plugins-dependencies
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"image_picker","path":"/Users/lolq/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker-0.6.6+1/","dependencies":[]},{"name":"image_cropper","path":"/Users/lolq/workspace/flutter_image_cropper/","dependencies":[]}],"android":[{"name":"flutter_plugin_android_lifecycle","path":"/Users/lolq/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-1.0.7/","dependencies":[]},{"name":"image_picker","path":"/Users/lolq/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker-0.6.6+1/","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_cropper","path":"/Users/lolq/workspace/flutter_image_cropper/","dependencies":["flutter_plugin_android_lifecycle"]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"image_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_cropper","dependencies":["flutter_plugin_android_lifecycle"]}],"date_created":"2020-05-12 18:42:18.873526","version":"1.18.0-11.0.pre.6"}
19 changes: 19 additions & 0 deletions example/android/android.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/../build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
Loading