gre / react-native-view-shot

Snapshot a React Native view and save it to an image
https://github.com/gre/react-native-view-shot-example
MIT License
2.66k stars 346 forks source link

Camera View working on iOS but not on Android? #448

Closed soemarko closed 1 year ago

soemarko commented 1 year ago

bug report

Version & Platform

npm ls react-native react-native-view-shot #<- PASTE CMD RESULT IN HERE
├─┬ @api.video/react-native-livestream@1.2.1
│ └── react-native@0.70.5 deduped
├─┬ react-native-view-shot@3.5.0
│ └── react-native@0.70.5 deduped
└── react-native@0.70.5

Platform: iOS & Android

Expected behavior

Based on the interoperability table with react-native-camera, honestly, I expected the other way around, but ideally it works for both iOS and Android.

Actual behavior

I can capture a snapshot on iOS but black image on Android.

Steps to reproduce the behavior

  1. Create Livestream View with @api.video/react-native-livestream
  2. Add a button to capture a screenshot

The whole screen is below

import { StyleSheet, TouchableOpacity, View, Text, Share } from 'react-native'
import React, { useRef, useState } from 'react';
import { LiveStreamView } from '@api.video/react-native-livestream';
import { activateKeepAwake, deactivateKeepAwake } from "@sayem314/react-native-keep-awake";
import ViewShot, { captureScreen, captureRef } from "react-native-view-shot";
import { Image } from 'react-native';

export default function Broadcast() {
  const ref = useRef(null);
  const viewRef = useRef(null);
  const [streaming, setStreaming] = useState(false);
  const [camera, setCamera] = useState('back');
  const [image, setImage] = useState('https://unsplash.it/200/200');

  return (
    <View style={styles.container}>
      <ViewShot ref={viewRef} style={styles.container}>
        <LiveStreamView
          style={{ flex: 1, backgroundColor: 'black', alignSelf: 'stretch' }}
          ref={ref}
          camera={camera}
          video={{
            fps: 30,
            resolution: '480p',
            bitrate: 1*1024*1024, // # 1 Mbps
          }}
          audio={{
            bitrate: 128000,
            sampleRate: 44100,
            isStereo: true,
          }}
          isMuted={false}
          onConnectionSuccess={() => {
            //do what you want
          }}
          onConnectionFailed={(e) => {
            //do what you want
          }}
          onDisconnect={() => {
            //do what you want
          }}
        />
        </ViewShot>
      <View style={styles.buttonContainer}>
        <TouchableOpacity
          style={{
            borderRadius: 50,
            backgroundColor: streaming ? 'red' : 'white',
            width: 50,
            height: 50,
            marginHorizontal: 10
          }}
          onPress={() => {
            if (streaming) {
              ref.current?.stopStreaming();
              deactivateKeepAwake();
              setStreaming(false);
            } else {
              ref.current?.startStreaming(streamurl);
              activateKeepAwake();
              setStreaming(true);
            }
          }}
        />
        <TouchableOpacity
          style={{
            borderRadius: 50,
            backgroundColor: 'blue',
            width: 50,
            height: 50,
            marginHorizontal: 10,
            justifyContent: 'center',
            alignItems: 'center'
          }}
          onPress={() => {
            if(camera == 'back') setCamera('front');
            else setCamera('back');
          }}
        >
          <Text style={{color: 'white'}}>flip</Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={{
            borderRadius: 50,
            backgroundColor: 'orange',
            width: 50,
            height: 50,
            marginHorizontal: 10,
            justifyContent: 'center',
            alignItems: 'center'
          }}
          onPress={() => {
            captureScreen({
              format: "jpg",
              quality: 0.8,
            }).then(
              (uri) => {
                console.log('snap', uri);
                setImage(uri);
                // Share.share({title: 'ss', url: uri});
              },
              (error) => console.error("Oops, snapshot failed", error)
            );
          }}
        >
          <Text style={{color: 'white'}}>snap</Text>
        </TouchableOpacity>
      </View>
      <View style={styles.imageContainer}>
        <Image
          style={{width: 200, height:200}}
          source={{uri: image}}
          alt="snap"
        />
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  buttonContainer: {
    position: 'absolute',
    bottom: 80,
    alignSelf: 'center',
    flexDirection: 'row'
  },
  imageContainer: {
    position: 'absolute',
    top: 0,
    right: 0,
    width: 200,
    height: 200,
    flexDirection: 'row',
    backgroundColor: 'orange',
    opacity: 0.8
  }
});
gre commented 1 year ago

i'm afraid this is out of scope of this library. unless you have a fix that makes it work, it is probably a technical problem at the native level & it is preferrable to try to look for a solution to directly use the camera api on the native side.