@blockfact/react-native-facti
v1.0.5
Published
React Native component for displaying and verifying .facti files
Downloads
610
Maintainers
Readme
@blockfact/react-native-facti
React Native component for displaying and verifying .facti files.
Installation
npm install @blockfact/react-native-facti
# or
yarn add @blockfact/react-native-factiUsage
Basic Display
import FactiImage from '@blockfact/react-native-facti';
function Gallery() {
return (
<FactiImage
factiUrl="https://gateway.pinata.cloud/ipfs/QmXXX"
style={{ marginVertical: 20 }}
/>
);
}With Metadata Overlay
<FactiImage
factiUrl="https://gateway.pinata.cloud/ipfs/QmXXX"
showMetadata={true}
onMetadataLoad={(metadata) => {
console.log('Loaded:', metadata.tx_hash);
}}
/>Parse .facti File Manually
import { parseFacTi } from '@blockfact/react-native-facti';
async function loadFacti() {
const { imageUri, metadata } = await parseFacTi(
'https://gateway.pinata.cloud/ipfs/QmXXX'
);
console.log('Transaction:', metadata.tx_hash);
console.log('Owner:', metadata.wallet);
console.log('GPS:', metadata.latitude, metadata.longitude);
// Use imageUri in Image component
<Image source={{ uri: imageUri }} />
}Custom Metadata Display
import { parseFacTi } from '@blockfact/react-native-facti';
import { View, Image, Text } from 'react-native';
function CustomFactiView({ factiUrl }) {
const [data, setData] = useState(null);
useEffect(() => {
parseFacTi(factiUrl).then(setData);
}, [factiUrl]);
if (!data) return <Text>Loading...</Text>;
return (
<View>
<Image source={{ uri: data.imageUri }} style={{ width: 300, height: 300 }} />
<Text>Owner: {data.metadata.wallet}</Text>
<Text>Location: {data.metadata.latitude}, {data.metadata.longitude}</Text>
</View>
);
}Component Props
FactiImage
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| factiUrl | string | required | URL to .facti file (IPFS, HTTP, etc.) |
| style | object | {} | Style for container View |
| showMetadata | boolean | false | Show verification badge overlay |
| onMetadataLoad | function | null | Callback when metadata is loaded |
API
parseFacTi(factiUrl)
Parses a .facti file and returns image + metadata.
Parameters:
factiUrl(string) - URL to .facti file
Returns:
{
imageUri: "data:image/png;base64,...", // Base64 data URI
metadata: {
tx_hash: "0x...",
wallet: "0x...",
timestamp: "2026-02-26T13:20:00Z",
latitude: 40.7128,
longitude: -74.0060,
session_id: "preprocess-...",
// ... other fields
}
}Features
- ✅ Parse .facti files from any URL
- ✅ Display watermarked image
- ✅ Show metadata (transaction, owner, GPS, timestamp)
- ✅ Clickable blockchain verification link
- ✅ Clickable GPS coordinates (opens Google Maps)
- ✅ Verification badge overlay
- ✅ Error handling
- ✅ Loading states
File Format Support
Supports .facti v1.0+ with structure:
- Magic number (4 bytes):
0xFA 0x49 0x01 0x00 - Metadata hash (32 bytes)
- Metadata length (4 bytes, big-endian)
- Metadata JSON (N bytes)
- Image data (M bytes)
Examples
Gallery View
import { FlatList } from 'react-native';
import FactiImage from './FactiImage';
const factiFiles = [
'https://gateway.pinata.cloud/ipfs/QmAAA',
'https://gateway.pinata.cloud/ipfs/QmBBB',
'https://gateway.pinata.cloud/ipfs/QmCCC',
];
function FactiGallery() {
return (
<FlatList
data={factiFiles}
renderItem={({ item }) => (
<FactiImage
factiUrl={item}
showMetadata={true}
style={{ marginBottom: 20 }}
/>
)}
keyExtractor={(item) => item}
/>
);
}Upload from Device
import * as DocumentPicker from 'expo-document-picker';
import { parseFacTi } from './FactiImage';
async function pickFactiFile() {
const result = await DocumentPicker.getDocumentAsync({
type: '*/*',
});
if (result.type === 'success') {
// Read file as base64
const base64 = await FileSystem.readAsStringAsync(result.uri, {
encoding: FileSystem.EncodingType.Base64,
});
// Convert to data URL
const dataUrl = `data:application/octet-stream;base64,${base64}`;
// Parse
const { imageUri, metadata } = await parseFacTi(dataUrl);
console.log('Loaded local .facti file:', metadata);
}
}Verification Screen
function VerificationScreen({ factiUrl }) {
const [metadata, setMetadata] = useState(null);
return (
<ScrollView>
<FactiImage
factiUrl={factiUrl}
onMetadataLoad={setMetadata}
/>
{metadata && (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>
✅ Blockchain Verified
</Text>
<Text>Transaction: {metadata.tx_hash}</Text>
<Text>Timestamp: {new Date(metadata.timestamp).toLocaleString()}</Text>
</View>
)}
</ScrollView>
);
}Notes
- Works with Expo and bare React Native
- No native modules required
- Uses standard Web APIs (fetch, TextDecoder, Uint8Array)
- Images converted to base64 data URIs for React Native compatibility
- Supports both PNG and JPEG images
Troubleshooting
"Invalid .facti file format"
- File doesn't start with magic number
0xFA 0x49 0x01 0x00 - Verify URL is correct and file is accessible
Image not displaying
- Check that image data is valid PNG/JPEG
- Verify base64 conversion is working
- Try logging
imageUrito debug
Metadata parsing error
- JSON in .facti file may be corrupted
- Check metadata length field is correct
