How to draw over other apps in React-native?

前端 未结 1 820
谎友^
谎友^ 2021-01-14 10:58

I need to have something similar to Facebook Messenger\'s chat heads in my app, basically a bubble that can be viewed over other apps. I can\'t find anything online on this

相关标签:
1条回答
  • 2021-01-14 11:41

    this feature is not support directly from react native and also this is not supported in ios therefore only you could implement it with java native code in android. to do that you should write a service in android which handle this element life cycle. You could find here simple implementation of that in an android project. it's such a straightforward example and you can use it's service for your react native project and just change it's xml file to customize your view. And just to start your service you must write a very simple react native module look like this

    @ReactMethod
    public void startService(Promise promise) {
    
        String result = "Success";
        Activity activity = getCurrentActivity();
        if (activity != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(getReactApplicationContext())) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:" + getCurrentActivity().getPackageName()));
                getCurrentActivity().startActivityForResult(intent, MainActivity.DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE);
            }
        }
        try {
            Intent intent = new Intent(FloatingWidgetService.FLOATING_WIDGET_ID);
            intent.setClass(this.getReactApplicationContext(), FloatingWidgetService.class);
            getReactApplicationContext().startService(intent);
            FloatingWidgetService.setUri(uri);
        } catch (Exception e) {
            promise.reject(e);
            return;
        }
        promise.resolve(result);
    }
    

    in Android-8Oreo you must ask for canDrawOverlays and you can wait for result in your MainActivity like this:

    private static final int DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE = 1222;
    ....
    private void startFloatingWidgetService() {
        if (!mStarted) {
            Intent intent = new Intent(this, FloatingWidgetService.class);
            ContextCompat.startForegroundService(this, intent);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                this.startForegroundService(intent);
            }else{
                startService(intent);
            }
            mStarted = true;
            finish();
        }
    }
    ....
     @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE) {
                //Check if the permission is granted or not.
                if (resultCode == RESULT_OK)
                    //If permission granted start floating widget service
                    startFloatingWidgetService();
                else
                    //Permission is not available then display toast
                    Toast.makeText(this,
                            getResources().getString(R.string.draw_other_app_permission_denied),
                            Toast.LENGTH_SHORT).show();
    
            } else {
                super.onActivityResult(requestCode, resultCode, data);
            }
        }
    

    And after that to come back again to your app from that service with the same appstate(not to create new activity) first define your activity launchmode as a singleInstance in manifest:

    <activity
            ...
            android:launchMode="singleInstance"
            ...
            >
    

    And use this kind of intent(!) in your service:

    ReactApplicationContext reactContext = VideoViewModule.getReactContext();
    Intent activityIntent = createSingleInstanceIntent();
    reactContext.startActivity(activityIntent);
    
    
    
     private Intent createSingleInstanceIntent() {
            ReactApplicationContext reactContext = VideoViewModule.getReactContext();
            String packageName = reactContext.getPackageName();
            Intent launchIntent = reactContext.getPackageManager().getLaunchIntentForPackage(packageName);
            String className = launchIntent.getComponent().getClassName();
            Intent activityIntent = null;
            try {
    
                Class<?> activityClass = Class.forName(className);
    
                activityIntent = new Intent(reactContext, activityClass);
    
                activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    
            } catch (Exception e) {
                stopCurrentService();
                Log.e("POIFOIWEGBF", "Class not found", e);
    
            }
            return activityIntent;
        }
    

    I hope it helps.

    0 讨论(0)
提交回复
热议问题