Sådan bygges reaktivt-bro og få PDF-visning

React Native giver mulighed for at bygge oprindelige applikationer ved hjælp af JavaScript-sprog og har enorme mængder af komponenter og funktionalitet til rådighed. Men nogle komponenter eller funktioner er ikke tilgængelige som standard. Og nogle gange er det nødvendigt at forbedre ydelsen for nogle komponenter. I disse tilfælde kan native implementering bruges.

Denne artikel beskriver, hvordan man opretter en bro mellem JavaScript og en oprindelig implementering og giver et eksempel på, hvordan man bygger en PDF-visning til React Native til gengivelse af PDF-dokumenter.

Alle kilder er tilgængelige i gitlab eller som NPM-pakke:

  • NPM-pakke react-native-view-pdf (https://www.npmjs.com/package/react-native-view-pdf)
  • Gitlab kilder rumax / react-native-PDFView (https://github.com/rumax/react-native-PDFView)

Kom godt i gang

Forbered først et projekt. Åbn en terminal og kør:

$ create-react-native-app react-native-PDFView
$ cd react-native-PDFView
$ garn skubber ud

Kontroller, at projektet fungerer:

$ garn køre android

og åbn den i IDE. Jeg foretrækker Atom, derfor kan jeg i terminal gøre:

$ atom.

Åbn Android Studio for at arbejde med Java-kilder.

Java-implementering

I Android Studio:

  • oprette ny pakke realibrær
  • oprette nye Java-klasser PDFView, PDFViewManager og PDFViewPackage

PDFViewPackage

I henhold til officiel dokumentation skal PDFViewPackage implementere ReactPackage og manglende createNativeModules og createViewManagers-metoder bør tilføjes:

public class PDFViewPackage implementerer ReactPackage {
    @Override
    public List  createNativeModules (ReactApplicationContext reactContext) {
        returner Collections.emptyList ();
    }
    offentlig liste  createViewManagers (ReactApplicationContext reactContext) {
        return Arrays.  asList (ny PDFViewManager (reactContext));
    }
}

Android Studio vil fremhæve en fejl, PDFViewManager kan ikke anvendes til ..., som skal rettes ved at implementere PDFViewManager.

PDFViewManager

PDFViewManager skal udvide SimpleViewManager og implementere manglende metoder:

  • getName hvilket - skal returnere navnet på reaktionsklassen
  • createViewInstance er et sted, hvor seeren skal initialiseres

Koden er:

public class PDFViewManager udvider SimpleViewManager  {
    privat statisk final String REACT_CLASS = "PDFView";
    privat PDFView pdfView = null;
    privat kontekstkontekst;
    offentlig PDFViewManager (ReactApplicationContext-kontekst) {
        this.context = kontekst;
    }
    @Override
    public String getName () {
        returner REACT_CLASS;
    }
    @Override
    offentlig PDFView createViewInstance (ThemedReactContext-kontekst) {
        if (pdfView == null) {
            pdfView = ny PDFView (kontekst);
        }
        return pdfView;
    }
}

med den fejl, at PDFView skal udvide View, som skal rettes ved implementering af PDFView.

PDFView

PDFView skal udvide android.view.View, og implementeringen er ret enkel:

public class PDFView udvider android.view.View {
    privat ThemedReactContext kontekst;
    offentlig PDFView (ThemedReactContext-kontekst) {
        super (kontekst);
        this.context = kontekst;
    }
}

På dette tidspunkt er alle klasser klar, og PDFViewPackagecan kan registreres.

Registrer PDFViewPackage

I MainApplication.java findes getPackages-metoden. Lige nedenfor MainReactPackage kan PDFViewPackage-pakken registreres:

@Override
beskyttet liste  getPakker () {
  return Arrays.  asList (
      ny MainReactPackage (),
      ny PDFViewPackage ()
  );
}

Første implementering af Java er klar!

JavaScript-implementering

Opret en ny mappe PDFView i Atom og opret to filer:

  • index.js
  • RNPDFView.js

PDFView / RNPDFView.js

Dette er hovedfil, hvor PDFView-reaktionskomponenten skal være påkrævet, og komponentgrænsefladen skal defineres:

import {kræver NativeComponent, ViewPropTypes} fra 'react-native';
import PropTypes fra 'prop-typer';
const componentInterface = {
  navn: 'PDFView',
  proptyper: {
    ... ViewPropTypes,
  },
};
eksport standard kræver NativeComponent ('PDFView', componentInterface);

I dette øjeblik bruges kun ViewPropTypes til at kontrollere, at komponenten er korrekt defineret og kan bruges. Alle andre egenskaber tilføjes senere.

PDFView / index.js

Denne fil er valgfri og kan bruges som indpakningskomponent, til at håndtere fejl / indlæsningstilstande eller til at bruge flowtyper osv.:

/ * @ flow * /
import React fra 'react';
importer RNPDFView fra './RNPDFView';
skriv Props = {};
klasse PDFView udvider React.Component  {
  statisk defaultProps = {};
  konstruktør (rekvisitter: rekvisitter) {
    super (rekvisitter);
  }
  render () {
    returner ;
  }
}
eksport standard PDFView;

App.js

Broen er klar og kan importeres og bruges:

import PDFView fra './PDFView/index';
...
Vend tilbage (
  
    
  
);

Da det implementerer android.view.View i Java, skal det også opføre sig som en View-native-komponent. Dette kan kontrolleres ved at definere stilarter:

const styles = StyleSheet.create ({
  pdfView: {
    højde: 400,
    bredde: 300,
    baggrund Farve: 'grøn',
  },
  ...

Genstart appen, så får du et grønt rektangel som dette:

Styling af komponenten

Det er faktisk alt for broen, bortset fra egenskaber og tilbagekald. Og hvis de ikke er påkrævet, er det allerede muligt at implementere komponenten i Java.

PDF Viewer-implementering

For at implementere PDF Viewer er det nødvendigt at vide:

  • ressource - strengværdi til at definere den ressource, der skal gengives. Kan være url-, filePath- eller base64-data
  • resourceType - String-værdi til at definere ressource-typen

Og selvfølgelig få nogle feedback fra oprindelig del til JavaScript:

  • onError - der skal aktiveres tilbagekaldsfunktion ved en fejl
  • onLoad - Opkaldsfunktion, der skal aktiveres, når belastningen er afsluttet

Videregive egenskaber fra JavaScript

I PDFView / RNPDFView.js udvides componentInterface.propTypes med de egenskaber, der er beskrevet ovenfor:

const componentInterface = {
  navn: 'PDFView',
  proptyper: {
    onError: PropTypes.func,
    onLoad: PropTypes.func,
    resource: PropTypes.string,
    resourceType: PropTypes.string,
    ... ViewPropTypes,
  },
};

Gør det samme i PDFView / index.js men ved hjælp af flowtyper:

type Props = {
  onError: (Fejl) => annulleret,
  onLoad: () => ugyldigt,
  ressource: streng,
  resourceType: 'url' | 'base64' | 'fil',
};

Og definer metode onError til kun at videregive nativeEvent fra komponenten:

onError: (error: Error) => annulleret; // Definition af flowtype
onError (event: any) {
  this.props.onError (event && event.nativeEvent || new Error ());
}

Glem ikke at binde dette i konstruktøren:

konstruktør (rekvisitter: rekvisitter) {
  super (rekvisitter);
  this.onError = this.onError.bind (dette);
}

Og fix gengivelsesmetoden:

render () {
  const {onError, ... restenProps} = this.props;
  returner ;
}

Standardegenskaber kan også defineres for at forenkle brugen af ​​komponenten:

statisk defaultProps = {
  onError: () => {},
  onLoad: () => {},
  resourceType: 'url',
};

JavaScript-implementeringen er færdig nu.

Hent og brug egenskaber i Java

Skift til Android Studio, og åbn klassen PDFViewManager. Dette er stedet, hvor alle egenskaber, defineret i JavaScript, kan fås. Definer ressource:

@ReactProp (navn = "ressource")
public void setResource (PDFView pdfView, strengressource) {
    pdfView.setResource (ressource);
}

Og det samme for resourceType (tilbagekald vil blive implementeret senere):

@ReactProp (name = "resourceType")
public void setResourceType (PDFView pdfView, String resourceType) {
    pdfView.setResourceType (resourceType);
}

Implementering i PDFView-klassen vil være:

privat String resourceType;
privat strengressource;
    
public void setResource (String resource) {
    this.resource = resource;
}
public void setResourceType (String resourceType) {
    this.resourceType = resourceType;
}

Find følgende metoder i PDFViewManager:

  • onAfterUpdateTransaction er dette stedet, hvor komponenten skal gengives, når alle egenskaber er indstillet:
@Override
offentlig annullering onAfterUpdateTransaction (PDFView pdfView) {
    super.onAfterUpdateTransaction (pdfView);
    pdfView.render ();
}
  • onDropViewInstance dette er en anden metode, der kaldes, når React Native-komponenten ikke er monteret. Implementeringen kan være følgende:
@Override
public void onDropViewInstance (PDFView pdfView) {
    super.onDropViewInstance (pdfView);
    pdfView.onDrop ();
}

Brug tilbagekald af JavaScript i Java

For at bruge belastningen er fuldført, er der fejl ved tilbagekald, som det er nødvendigt at videregive denne begivenhed. Åbn PDFView.java og definerer loadComplete og onError metoder:

@Override
public void loadComplete (int numberOfPages) {
    reactNativeEvent ("onLoad", null);
}
@Override
public void onError (Exception ex) {
    reactNativeEvent ("onError", "error:" + t.getMessage ());
}

og implementere reactNativeEvent-metoden. I henhold til officiel dokumentation skal det være:

private void reactNativeEvent (String eventName, String message) {
    WritableMap event = Arguments.createMap ();
    event.putString ("besked", besked);
    ReactContext reactContext = (ReactContext) this.getContext ();
    reactContext
            .getJSModule (RCTEventEmitter.class)
            .receiveEvent (this.getId (), eventName, event);
}

Og i PDFViewManager

public Map getExportedCustomBubblingEventTypeConstants () {
    returner MapBuilder
            .Bygger()
            .sætte(
                    "OnLoad",
                    MapBuilder.of ("phasedRegistrationNames", MapBuilder.of ("boblet", "onLoad"))
            )
            .sætte(
                    "OnError",
                    MapBuilder.of ("phasedRegistrationNames", MapBuilder.of ("boblet", "onError"))
            )
            .build ();
}

Implementeringen af ​​broen er klar! Det eneste, der er tilbage at gøre, er at implementere PDFViewer.java. Jeg brugte AndroidPdfViewer-implementering og den endelige løsning, du kan finde i gitlab (https://github.com/rumax/react-native-PDFView).

Resultater

Implementeringen af ​​broen og PDF Viewer er klar. Definer det dokument, du gerne vil gengive:


   console.log ('onError', error)}
    onLoad = {() => console.log ('onLoad')}
    resource = "http://www.pdf995.com/samples/pdf.pdf" />

..læs programmet igen, og i stedet for det grønne rektangel får du PDF-dokument:

PDF Viewer-resultater