mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-05 22:56:11 +00:00
feat: support dataUri for android platform (#2396)
# Summary Closes #1318 Add support data URI in the Android platform. It already works on the iOS platform. | Before1 | Before2 | After | |--------|--------|--------| |<img src="https://github.com/user-attachments/assets/4423ae12-0e67-4ff9-9a15-76fc6b707b26" width="300" height="600" /> | <img src="https://github.com/user-attachments/assets/a4412e8e-d965-41e9-95f3-06bffc6ebb76" width="300" height="600" /> | <img src="https://github.com/user-attachments/assets/69ba40ac-de52-4edf-9850-ea870270f426" width="300" height="600" /> | ## Compatibility | OS | Implemented | | ------- | :---------: | | Android | ✅ |
This commit is contained in:
@@ -4,6 +4,7 @@ import React from 'react';
|
||||
import ColorTest from './src/ColorTest';
|
||||
import PointerEventsBoxNone from './src/PointerEventsBoxNone';
|
||||
import MountUnmount from './src/MountUnmount';
|
||||
import Test1318 from './src/Test1318';
|
||||
import Test1374 from './src/Test1374';
|
||||
import Test1442 from './src/Test1442';
|
||||
import Test1451 from './src/Test1451';
|
||||
|
||||
31
apps/test-examples/src/Test1318.tsx
Normal file
31
apps/test-examples/src/Test1318.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import {SvgUri} from 'react-native-svg';
|
||||
import {SvgCssUri} from 'react-native-svg/css';
|
||||
|
||||
export default function Test() {
|
||||
return (
|
||||
<>
|
||||
<SvgCssUri
|
||||
height={100}
|
||||
width={100}
|
||||
uri={
|
||||
'data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20100%20100%22%3E%3Cpath%20fill%3D%22%2354b847%22%20d%3D%22M0%200h100v100H0z%22%2F%3E%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M61.6%2069.1h-17V38.3h8.6v25.4h8.2c5.7%200%208.1-3.9%208.1-14.1S66.8%2036.4%2061%2036.4H42.2v32.7h-8.4V36.3H21.4v-5.4h42.3c10.2%200%2015%205.3%2015%2018.6-.1%2017.4-7.3%2019.6-17.1%2019.6%22%2F%3E%3C%2Fsvg%3E'
|
||||
}
|
||||
/>
|
||||
<SvgCssUri
|
||||
height={100}
|
||||
width={100}
|
||||
uri={
|
||||
'data:image/svg+xml;utf8,%3Csvg%20width%3D%22300%22%20height%3D%22700%22%20viewBox%3D%2250%2050%20100%20100%22%20preserveAspectRatio%3D%22xMidYMid%20meet%22%3E%3Crect%20x%3D%2250%22%20y%3D%2250%22%20width%3D%22100%22%20height%3D%22100%22%20fill%3D%22yellow%22%3E%3C%2Frect%3E%3C%2Fsvg%3E'
|
||||
}
|
||||
/>
|
||||
<SvgUri
|
||||
height={100}
|
||||
width={100}
|
||||
uri={
|
||||
'data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%22%20height%3D%22100%22%20viewBox%3D%220%200%20100%20100%22%3E%3Cpolygon%20points%3D%2250%2C15%2061%2C40%2088%2C40%2066%2C57%2075%2C84%2050%2C68%2025%2C84%2034%2C57%2012%2C40%2039%2C40%22%20fill%3D%22gold%22%2F%3E%3C%2Fsvg%3E'
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import Shape from './elements/Shape';
|
||||
import {
|
||||
AstProps,
|
||||
camelCase,
|
||||
fetchText,
|
||||
JsxAST,
|
||||
Middleware,
|
||||
parse,
|
||||
@@ -19,6 +18,8 @@ import {
|
||||
XmlState,
|
||||
} from './xml';
|
||||
|
||||
import { fetchText } from './utils/fetchData';
|
||||
|
||||
import {
|
||||
RNSVGCircle,
|
||||
RNSVGClipPath,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
AstProps,
|
||||
camelCase,
|
||||
fetchText,
|
||||
JsxAST,
|
||||
Middleware,
|
||||
parse,
|
||||
@@ -18,6 +17,8 @@ import {
|
||||
XmlState,
|
||||
} from './xml';
|
||||
|
||||
import { fetchText } from './utils/fetchData';
|
||||
|
||||
export {
|
||||
inlineStyles,
|
||||
loadLocalRawResource,
|
||||
|
||||
29
src/utils/fetchData.ts
Normal file
29
src/utils/fetchData.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
export async function fetchText(uri?: string): Promise<string | null> {
|
||||
if (!uri) {
|
||||
return null;
|
||||
}
|
||||
if (uri.startsWith('data:image/svg+xml;utf8') && Platform.OS === 'android') {
|
||||
return dataUriToXml(uri);
|
||||
} else {
|
||||
return fetchUriData(uri);
|
||||
}
|
||||
}
|
||||
|
||||
function dataUriToXml(uri: string): string | null {
|
||||
try {
|
||||
// decode and remove data:image/svg+xml;utf8, prefix
|
||||
return decodeURIComponent(uri).split(',').slice(1).join(',');
|
||||
} catch (error) {
|
||||
throw new Error(`Decoding ${uri} failed with error: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchUriData(uri: string) {
|
||||
const response = await fetch(uri);
|
||||
if (response.ok || (response.status === 0 && uri.startsWith('file://'))) {
|
||||
return await response.text();
|
||||
}
|
||||
throw new Error(`Fetching ${uri} failed with status ${response.status}`);
|
||||
}
|
||||
12
src/xml.tsx
12
src/xml.tsx
@@ -1,6 +1,7 @@
|
||||
import type { ComponentType, ComponentProps } from 'react';
|
||||
import * as React from 'react';
|
||||
import { Component, useEffect, useMemo, useState } from 'react';
|
||||
import { fetchText } from './utils/fetchData';
|
||||
import type { SvgProps } from './elements/Svg';
|
||||
import { tags } from './xmlTags';
|
||||
|
||||
@@ -78,17 +79,6 @@ export function SvgXml(props: XmlProps) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchText(uri?: string) {
|
||||
if (!uri) {
|
||||
return null;
|
||||
}
|
||||
const response = await fetch(uri);
|
||||
if (response.ok || (response.status === 0 && uri.startsWith('file://'))) {
|
||||
return await response.text();
|
||||
}
|
||||
throw new Error(`Fetching ${uri} failed with status ${response.status}`);
|
||||
}
|
||||
|
||||
export function SvgUri(props: UriProps) {
|
||||
const { onError = err, uri, onLoad, fallback } = props;
|
||||
const [xml, setXml] = useState<string | null>(null);
|
||||
|
||||
Reference in New Issue
Block a user