Skip to content

Commit

Permalink
feat: ios preprocessing page (url metadata)
Browse files Browse the repository at this point in the history
  • Loading branch information
achorein committed Dec 21, 2024
1 parent d5bd3d5 commit a94fa81
Show file tree
Hide file tree
Showing 16 changed files with 446 additions and 154 deletions.
34 changes: 18 additions & 16 deletions README.md

Large diffs are not rendered by default.

49 changes: 45 additions & 4 deletions example/basic/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
import { Button, Image, StyleSheet, Text, View } from "react-native";

import { useShareIntent, ShareIntentFile } from "expo-share-intent";
import {
useShareIntent,
ShareIntentFile,
ShareIntent,
} from "expo-share-intent";
import { Fragment } from "react";

const WebUrlComponent = ({ shareIntent }: { shareIntent: ShareIntent }) => {
return (
<View
style={[
styles.gap,
styles.row,
{ borderWidth: 1, borderRadius: 5, height: 102 },
]}
>
<Image
source={
shareIntent.meta?.["og:image"]
? { uri: shareIntent.meta?.["og:image"] }
: undefined
}
style={[styles.icon, styles.gap, { borderRadius: 5 }]}
/>
<View style={{ flexShrink: 1, padding: 5 }}>
<Text style={[styles.gap]}>
{shareIntent.meta?.title || "<NO TITLE>"}
</Text>
<Text style={styles.gap}>{shareIntent.webUrl}</Text>
</View>
</View>
);
};

export default function App() {
const { hasShareIntent, shareIntent, resetShareIntent, error } =
useShareIntent({
Expand All @@ -22,8 +53,8 @@ export default function App() {

{/* TEXT and URL */}
{!!shareIntent.text && <Text style={styles.gap}>{shareIntent.text}</Text>}
{!!shareIntent.meta?.title && (
<Text style={styles.gap}>{JSON.stringify(shareIntent.meta)}</Text>
{shareIntent?.type === "weburl" && (
<WebUrlComponent shareIntent={shareIntent} />
)}

{/* FILES */}
Expand Down Expand Up @@ -69,6 +100,7 @@ const styles = StyleSheet.create({
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 10,
},
logo: {
width: 75,
Expand All @@ -79,7 +111,16 @@ const styles = StyleSheet.create({
width: 300,
height: 200,
resizeMode: "contain",
// backgroundColor: "lightgray",
},
icon: {
width: 100,
height: 100,
resizeMode: "contain",
backgroundColor: "lightgray",
},
row: {
flexDirection: "row",
gap: 10,
},
gap: {
marginBottom: 20,
Expand Down
4 changes: 1 addition & 3 deletions example/basic/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@
"NSExtensionActivationSupportsFileWithMaxCount": 1
},
"iosShareExtensionName": "ExpoShareIntent Example Extension",
"iosAppGroupIdentifier": "customgroup.expo.modules.exposhareintent.example",
"androidIntentFilters": ["text/*", "image/*", "video/*"],
"androidMultiIntentFilters": ["image/*"],
"disableIOS": false,
"disableAndroid": false
"preprocessorInjectJS": "metas['og\\:image'] = metas['og\\:image'] || document.querySelector('img#main-image')?.getAttribute('src') ;"
}
],
["expo-updates"]
Expand Down
2 changes: 2 additions & 0 deletions example/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"test:fix": "expo install --fix",
"doctor": "npx --yes expo-doctor@latest",
"lint": "eslint .",
"open:ios": "open -a \"Xcode\" ios",
"open:android": "open -a \"Android Studio\" android",
"postinstall": "patch-package"
},
"dependencies": {
Expand Down
47 changes: 44 additions & 3 deletions example/expo-router/app/shareintent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
import { Button, Image, StyleSheet, Text, View } from "react-native";

import { useRouter } from "expo-router";
import { useShareIntentContext } from "expo-share-intent";
import {
ShareIntent as ShareIntentType,
useShareIntentContext,
} from "expo-share-intent";

const WebUrlComponent = ({ shareIntent }: { shareIntent: ShareIntentType }) => {
return (
<View
style={[
styles.gap,
styles.row,
{ borderWidth: 1, borderRadius: 5, height: 102 },
]}
>
<Image
source={
shareIntent.meta?.["og:image"]
? { uri: shareIntent.meta?.["og:image"] }
: undefined
}
style={[styles.icon, styles.gap, { borderRadius: 5 }]}
/>
<View style={{ flexShrink: 1, padding: 5 }}>
<Text style={[styles.gap]}>
{shareIntent.meta?.title || "<NO TITLE>"}
</Text>
<Text style={styles.gap}>{shareIntent.webUrl}</Text>
</View>
</View>
);
};

export default function ShareIntent() {
const router = useRouter();
Expand All @@ -21,8 +51,8 @@ export default function ShareIntent() {
</Text>
)}
{!!shareIntent.text && <Text style={styles.gap}>{shareIntent.text}</Text>}
{!!shareIntent.meta?.title && (
<Text style={styles.gap}>{JSON.stringify(shareIntent.meta)}</Text>
{shareIntent?.type === "weburl" && (
<WebUrlComponent shareIntent={shareIntent} />
)}
{shareIntent?.files?.map((file) => (
<Image
Expand All @@ -46,6 +76,7 @@ const styles = StyleSheet.create({
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 10,
},
logo: {
width: 75,
Expand All @@ -57,6 +88,16 @@ const styles = StyleSheet.create({
height: 200,
resizeMode: "contain",
},
icon: {
width: 100,
height: 100,
resizeMode: "contain",
backgroundColor: "lightgray",
},
row: {
flexDirection: "row",
gap: 10,
},
gap: {
marginBottom: 20,
},
Expand Down
44 changes: 41 additions & 3 deletions example/react-navigation/app/ShareIntentScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
import { Button, Image, StyleSheet, Text, View } from "react-native";
import { StackNavigationProp } from "@react-navigation/stack";

import { useShareIntentContext } from "expo-share-intent";
import { ShareIntent, useShareIntentContext } from "expo-share-intent";
import { RootStackParamList } from "./types";

interface Props {
navigation: StackNavigationProp<RootStackParamList, "ShareIntent">;
}

const WebUrlComponent = ({ shareIntent }: { shareIntent: ShareIntent }) => {
return (
<View
style={[
styles.gap,
styles.row,
{ borderWidth: 1, borderRadius: 5, height: 102 },
]}
>
<Image
source={
shareIntent.meta?.["og:image"]
? { uri: shareIntent.meta?.["og:image"] }
: undefined
}
style={[styles.icon, styles.gap, { borderRadius: 5 }]}
/>
<View style={{ flexShrink: 1, padding: 5 }}>
<Text style={[styles.gap]}>
{shareIntent.meta?.title || "<NO TITLE>"}
</Text>
<Text style={styles.gap}>{shareIntent.webUrl}</Text>
</View>
</View>
);
};

export default function ShareIntentScreen({ navigation }: Props) {
const { hasShareIntent, shareIntent, resetShareIntent, error } =
useShareIntentContext();
Expand All @@ -22,8 +49,8 @@ export default function ShareIntentScreen({ navigation }: Props) {
{hasShareIntent ? "SHARE INTENT FOUND !" : "NO SHARE INTENT DETECTED"}
</Text>
{!!shareIntent.text && <Text style={styles.gap}>{shareIntent.text}</Text>}
{!!shareIntent.meta?.title && (
<Text style={styles.gap}>{JSON.stringify(shareIntent.meta)}</Text>
{shareIntent?.type === "weburl" && (
<WebUrlComponent shareIntent={shareIntent} />
)}
{shareIntent?.files?.map((file) => (
<Image
Expand All @@ -48,6 +75,7 @@ const styles = StyleSheet.create({
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 10,
},
logo: {
width: 75,
Expand All @@ -59,6 +87,16 @@ const styles = StyleSheet.create({
height: 200,
resizeMode: "contain",
},
icon: {
width: 100,
height: 100,
resizeMode: "contain",
backgroundColor: "lightgray",
},
row: {
flexDirection: "row",
gap: 10,
},
gap: {
marginBottom: 20,
},
Expand Down
44 changes: 40 additions & 4 deletions ios/ExpoShareIntentModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public class ExpoShareIntentModule: Module {
if url.fragment == "media" {
if let key = url.host?.components(separatedBy: "=").last {
if let json = userDefaults?.object(forKey: key) as? Data {
let sharedArray = decode(data: json)
let sharedArray = decodeMedia(data: json)
let sharedMediaFiles: [SharedMediaFile] = sharedArray.compactMap {
if let path = getAbsolutePath(for: $0.path) {
if $0.type == .video && $0.thumbnail != nil {
Expand Down Expand Up @@ -92,7 +92,7 @@ public class ExpoShareIntentModule: Module {
} else if url.fragment == "file" {
if let key = url.host?.components(separatedBy: "=").last {
if let json = userDefaults?.object(forKey: key) as? Data {
let sharedArray = decode(data: json)
let sharedArray = decodeMedia(data: json)
let sharedMediaFiles: [SharedMediaFile] = sharedArray.compactMap {
if let path = getAbsolutePath(for: $0.path) {
return SharedMediaFile.init(
Expand All @@ -108,7 +108,20 @@ public class ExpoShareIntentModule: Module {
return "empty"
}
}
} else if url.fragment == "text" || url.fragment == "weburl" {
} else if url.fragment == "weburl" {
if let key = url.host?.components(separatedBy: "=").last {
if let json = userDefaults?.object(forKey: key) as? Data {
let sharedArray = decodeWebUrl(data: json)
let sharedWebUrls: [WebUrl] = sharedArray.compactMap {
return WebUrl.init(url: $0.url, meta: $0.meta)
}
guard let json = toJson(data: sharedWebUrls) else { return "[]" }
return "{ \"weburls\": \(json), \"type\": \"\(url.fragment!)\" }"
} else {
return "empty"
}
}
} else if url.fragment == "text" {
if let key = url.host?.components(separatedBy: "=").last {
if let sharedArray = userDefaults?.object(forKey: key) as? [String] {
latestText = sharedArray.joined(separator: ",")
Expand Down Expand Up @@ -190,10 +203,14 @@ public class ExpoShareIntentModule: Module {
return url
}

private func decode(data: Data) -> [SharedMediaFile] {
private func decodeMedia(data: Data) -> [SharedMediaFile] {
let encodedData = try? JSONDecoder().decode([SharedMediaFile].self, from: data)
return encodedData!
}
private func decodeWebUrl(data: Data) -> [WebUrl] {
let encodedData = try? JSONDecoder().decode([WebUrl].self, from: data)
return encodedData!
}

private func toJson(data: [SharedMediaFile]?) -> String? {
if data == nil {
Expand All @@ -203,12 +220,31 @@ public class ExpoShareIntentModule: Module {
let json = String(data: encodedData!, encoding: .utf8)!
return json
}

private func toJson(data: [WebUrl]?) -> String? {
if data == nil {
return nil
}
let encodedData = try? JSONEncoder().encode(data)
let json = String(data: encodedData!, encoding: .utf8)!
return json
}

struct ShareIntentText: Codable {
let text: String
let type: String // text / weburl
}

class WebUrl: Codable {
var url: String
var meta: String

init(url: String, meta: String) {
self.url = url
self.meta = meta
}
}

class SharedMediaFile: Codable {
var path: String // can be image, video or url path
var thumbnail: String? // video thumbnail
Expand Down
Loading

0 comments on commit a94fa81

Please sign in to comment.