36
									
								
								Example/expoUsePushy/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,36 @@ | |||||||
|  | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files | ||||||
|  |  | ||||||
|  | # dependencies | ||||||
|  | node_modules/ | ||||||
|  |  | ||||||
|  | # Expo | ||||||
|  | .expo/ | ||||||
|  | dist/ | ||||||
|  | web-build/ | ||||||
|  | expo-env.d.ts | ||||||
|  |  | ||||||
|  | # Native | ||||||
|  | *.orig.* | ||||||
|  | *.jks | ||||||
|  | *.p8 | ||||||
|  | *.p12 | ||||||
|  | *.key | ||||||
|  | *.mobileprovision | ||||||
|  |  | ||||||
|  | # Metro | ||||||
|  | .metro-health-check* | ||||||
|  |  | ||||||
|  | # debug | ||||||
|  | npm-debug.* | ||||||
|  | yarn-debug.* | ||||||
|  | yarn-error.* | ||||||
|  |  | ||||||
|  | # macOS | ||||||
|  | .DS_Store | ||||||
|  | *.pem | ||||||
|  |  | ||||||
|  | # local env files | ||||||
|  | .env*.local | ||||||
|  |  | ||||||
|  | # typescript | ||||||
|  | *.tsbuildinfo | ||||||
							
								
								
									
										221
									
								
								Example/expoUsePushy/App.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,221 @@ | |||||||
|  | /* eslint-disable react/no-unstable-nested-components */ | ||||||
|  | /* eslint-disable react-native/no-inline-styles */ | ||||||
|  | import React, {useState} from 'react'; | ||||||
|  | import {StyleSheet, Text, View, TouchableOpacity, Image} from 'react-native'; | ||||||
|  |  | ||||||
|  | import TestConsole from './TestConsole'; | ||||||
|  |  | ||||||
|  | import _updateConfig from './update.json'; | ||||||
|  | import {PushyProvider, Pushy, usePushy} from 'react-native-update'; | ||||||
|  | const {appKey} = _updateConfig.android; | ||||||
|  |  | ||||||
|  | function Home() { | ||||||
|  |   const { | ||||||
|  |     client, | ||||||
|  |     checkUpdate, | ||||||
|  |     downloadUpdate, | ||||||
|  |     switchVersionLater, | ||||||
|  |     switchVersion, | ||||||
|  |     updateInfo, | ||||||
|  |     packageVersion, | ||||||
|  |     currentHash, | ||||||
|  |     progress: {received, total} = {}, | ||||||
|  |   } = usePushy(); | ||||||
|  |   const [useDefaultAlert, setUseDefaultAlert] = useState(false); | ||||||
|  |   const [showTestConsole, setShowTestConsole] = useState(false); | ||||||
|  |   const [showUpdateBanner, setShowUpdateBanner] = useState(false); | ||||||
|  |   const [showUpdateSnackbar, setShowUpdateSnackbar] = useState(false); | ||||||
|  |   // if (updateInfo) { | ||||||
|  |   //   updateInfo!.name = 'name'; | ||||||
|  |   //   updateInfo!.update = true; | ||||||
|  |   // } | ||||||
|  |   const snackbarVisible = | ||||||
|  |     !useDefaultAlert && showUpdateSnackbar && updateInfo?.update; | ||||||
|  |  | ||||||
|  |   if (showTestConsole) { | ||||||
|  |     return ( | ||||||
|  |       <TestConsole visible={true} onClose={() => setShowTestConsole(false)} /> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <View style={styles.container}> | ||||||
|  |       <Text style={styles.welcome}>欢迎使用Pushy热更新服务</Text> | ||||||
|  |       {/* <Text style={styles.welcome}>😁hdiffFromAPP更新成功!!!</Text> */} | ||||||
|  |       {/* <Text style={styles.welcome}>😁hdiffFromPPk更新成功!!!</Text> */} | ||||||
|  |       <View style={{flexDirection: 'row'}}> | ||||||
|  |         <TouchableOpacity | ||||||
|  |           onPress={() => { | ||||||
|  |             client?.setOptions({ | ||||||
|  |               updateStrategy: !useDefaultAlert ? null : 'alwaysAlert', | ||||||
|  |             }); | ||||||
|  |             setShowUpdateSnackbar(useDefaultAlert); | ||||||
|  |             setUseDefaultAlert(!useDefaultAlert); | ||||||
|  |           }} | ||||||
|  |           style={{ | ||||||
|  |             flexDirection: 'row', | ||||||
|  |             alignItems: 'center', | ||||||
|  |           }}> | ||||||
|  |           <View | ||||||
|  |             style={{ | ||||||
|  |               width: 20, | ||||||
|  |               height: 20, | ||||||
|  |               borderWidth: 1, | ||||||
|  |               borderColor: '#999', | ||||||
|  |               backgroundColor: useDefaultAlert ? 'blue' : 'white', | ||||||
|  |               justifyContent: 'center', | ||||||
|  |               alignItems: 'center', | ||||||
|  |             }}> | ||||||
|  |             {useDefaultAlert && <Text style={{color: 'white'}}>✓</Text>} | ||||||
|  |           </View> | ||||||
|  |           <Text style={{marginLeft: 8}}> | ||||||
|  |             {' '} | ||||||
|  |             {useDefaultAlert ? '当前使用' : '当前不使用'}默认的alert更新提示 | ||||||
|  |           </Text> | ||||||
|  |         </TouchableOpacity> | ||||||
|  |       </View> | ||||||
|  |       <Image | ||||||
|  |         resizeMode={'contain'} | ||||||
|  |         source={require('./assets/shezhi.png')} | ||||||
|  |         style={styles.image} | ||||||
|  |       /> | ||||||
|  |       <Text style={styles.instructions}> | ||||||
|  |         这是版本一 {'\n'} | ||||||
|  |         当前原生包版本号: {packageVersion} | ||||||
|  |         {'\n'} | ||||||
|  |         当前热更新版本Hash: {currentHash || '(空)'} | ||||||
|  |         {'\n'} | ||||||
|  |       </Text> | ||||||
|  |       <Text> | ||||||
|  |         下载进度:{received} / {total} | ||||||
|  |       </Text> | ||||||
|  |       <TouchableOpacity | ||||||
|  |         onPress={() => { | ||||||
|  |           checkUpdate(); | ||||||
|  |           setShowUpdateSnackbar(true); | ||||||
|  |         }}> | ||||||
|  |         <Text style={styles.instructions}>点击这里检查更新</Text> | ||||||
|  |       </TouchableOpacity> | ||||||
|  |  | ||||||
|  |       <TouchableOpacity | ||||||
|  |         testID="testcase" | ||||||
|  |         style={{marginTop: 15}} | ||||||
|  |         onPress={() => { | ||||||
|  |           setShowTestConsole(true); | ||||||
|  |         }}> | ||||||
|  |         <Text style={styles.instructions}> | ||||||
|  |           react-native-update版本:{client?.version} | ||||||
|  |         </Text> | ||||||
|  |       </TouchableOpacity> | ||||||
|  |       {snackbarVisible && ( | ||||||
|  |         <View style={styles.overlay}> | ||||||
|  |           <View | ||||||
|  |             style={{ | ||||||
|  |               width: '100%', | ||||||
|  |               backgroundColor: '#333', | ||||||
|  |               padding: 16, | ||||||
|  |               flexDirection: 'row', | ||||||
|  |               justifyContent: 'space-between', | ||||||
|  |               alignItems: 'center', | ||||||
|  |             }}> | ||||||
|  |             <Text style={{color: 'white'}}> | ||||||
|  |               有新版本({updateInfo.name})可用,是否更新? | ||||||
|  |             </Text> | ||||||
|  |             <View style={{flexDirection: 'row'}}> | ||||||
|  |               <TouchableOpacity | ||||||
|  |                 onPress={() => setShowUpdateSnackbar(false)} | ||||||
|  |                 style={{marginRight: 10}}> | ||||||
|  |                 <Text style={{color: 'white'}}>取消</Text> | ||||||
|  |               </TouchableOpacity> | ||||||
|  |               <TouchableOpacity | ||||||
|  |                 onPress={async () => { | ||||||
|  |                   setShowUpdateSnackbar(false); | ||||||
|  |                   await downloadUpdate(); | ||||||
|  |                   setShowUpdateBanner(true); | ||||||
|  |                 }}> | ||||||
|  |                 <Text style={{color: '#2196F3'}}>更新</Text> | ||||||
|  |               </TouchableOpacity> | ||||||
|  |             </View> | ||||||
|  |           </View> | ||||||
|  |         </View> | ||||||
|  |       )} | ||||||
|  |       {showUpdateBanner && ( | ||||||
|  |         <View style={styles.overlay}> | ||||||
|  |           <View | ||||||
|  |             style={{ | ||||||
|  |               width: '100%', | ||||||
|  |               backgroundColor: '#fff', | ||||||
|  |               padding: 16, | ||||||
|  |               borderBottomWidth: 1, | ||||||
|  |               borderBottomColor: '#eee', | ||||||
|  |             }}> | ||||||
|  |             <View style={{flexDirection: 'row', alignItems: 'center'}}> | ||||||
|  |               <Text>更新已完成,是否立即重启?</Text> | ||||||
|  |             </View> | ||||||
|  |             <View | ||||||
|  |               style={{ | ||||||
|  |                 flexDirection: 'row', | ||||||
|  |                 justifyContent: 'flex-end', | ||||||
|  |                 marginTop: 10, | ||||||
|  |               }}> | ||||||
|  |               <TouchableOpacity | ||||||
|  |                 onPress={() => { | ||||||
|  |                   switchVersionLater(); | ||||||
|  |                   setShowUpdateBanner(false); | ||||||
|  |                 }} | ||||||
|  |                 style={{marginRight: 20}}> | ||||||
|  |                 <Text style={{color: '#2196F3'}}>下次再说</Text> | ||||||
|  |               </TouchableOpacity> | ||||||
|  |               <TouchableOpacity onPress={switchVersion}> | ||||||
|  |                 <Text style={{color: '#2196F3'}}>立即重启</Text> | ||||||
|  |               </TouchableOpacity> | ||||||
|  |             </View> | ||||||
|  |           </View> | ||||||
|  |         </View> | ||||||
|  |       )} | ||||||
|  |     </View> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const styles = StyleSheet.create({ | ||||||
|  |   overlay: { | ||||||
|  |     position: 'absolute', | ||||||
|  |     top: 0, | ||||||
|  |     left: 0, | ||||||
|  |     right: 0, | ||||||
|  |     bottom: 0, | ||||||
|  |     backgroundColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|  |     justifyContent: 'center', | ||||||
|  |     alignItems: 'center', | ||||||
|  |   }, | ||||||
|  |   container: { | ||||||
|  |     flex: 1, | ||||||
|  |     justifyContent: 'center', | ||||||
|  |     alignItems: 'center', | ||||||
|  |     backgroundColor: '#F5FCFF', | ||||||
|  |   }, | ||||||
|  |   welcome: { | ||||||
|  |     fontSize: 20, | ||||||
|  |     textAlign: 'center', | ||||||
|  |     margin: 10, | ||||||
|  |   }, | ||||||
|  |   instructions: { | ||||||
|  |     textAlign: 'center', | ||||||
|  |     color: '#333333', | ||||||
|  |     marginBottom: 5, | ||||||
|  |   }, | ||||||
|  |   image: {}, | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const pushyClient = new Pushy({ | ||||||
|  |   appKey, | ||||||
|  |   debug: true, | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | export default function HomeScreen() { | ||||||
|  |   return ( | ||||||
|  |     <PushyProvider client={pushyClient}> | ||||||
|  |       <Home /> | ||||||
|  |     </PushyProvider> | ||||||
|  |   ); | ||||||
|  | } | ||||||
							
								
								
									
										274
									
								
								Example/expoUsePushy/TestConsole.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,274 @@ | |||||||
|  | /* eslint-disable react-native/no-inline-styles */ | ||||||
|  | /* eslint-disable react/react-in-jsx-scope */ | ||||||
|  | import {useCallback, useMemo, useState} from 'react'; | ||||||
|  | import { | ||||||
|  |   ActivityIndicator, | ||||||
|  |   TextInput, | ||||||
|  |   Button, | ||||||
|  |   StyleSheet, | ||||||
|  |   SafeAreaView, | ||||||
|  |   Text, | ||||||
|  |   View, | ||||||
|  |   TouchableOpacity, | ||||||
|  | } from 'react-native'; | ||||||
|  |  | ||||||
|  | import {PushyModule} from 'react-native-update'; | ||||||
|  | const Hash = '9D5CE6EBA420717BE7E7D308B11F8207681B066C951D68F3994D19828F342474'; | ||||||
|  | const UUID = '00000000-0000-0000-0000-000000000000'; | ||||||
|  | const DownloadUrl = 'https://localhost:3000/diff.ppk-patch'; | ||||||
|  | const AppPatchDownloadUrl = 'https://github.com/bozaigao/test_pushy_server/raw/refs/heads/main/hdiff.app-patch'; | ||||||
|  | const AppPatchHash = 'f5ba92c7c04250d4b8a446c8267ef459'; | ||||||
|  | const PPKDownloadUrl = 'https://github.com/bozaigao/test_pushy_server/raw/refs/heads/main/hdiff.ppk-patch'; | ||||||
|  | const PPKPatchHash = '6b3d26b7d868d1f67aedadb7f0b342d9'; | ||||||
|  | const OriginHash = 'f5ba92c7c04250d4b8a446c8267ef459'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const CustomDialog = ({title, visible, onConfirm}) => { | ||||||
|  |   if (!visible) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <View style={styles.overlay}> | ||||||
|  |       <View style={styles.dialog}> | ||||||
|  |         <Text style={styles.title}>{title}</Text> | ||||||
|  |         <TouchableOpacity | ||||||
|  |           testID="done" | ||||||
|  |           style={styles.button} | ||||||
|  |           onPress={onConfirm}> | ||||||
|  |           <Text style={styles.buttonText}>确认</Text> | ||||||
|  |         </TouchableOpacity> | ||||||
|  |       </View> | ||||||
|  |     </View> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | export default function TestConsole({visible, onClose}) { | ||||||
|  |   const [text, setText] = useState(''); | ||||||
|  |   const [running, setRunning] = useState(false); | ||||||
|  |   const [options, setOptions] = useState(); | ||||||
|  |   const [alertVisible, setAlertVisible] = useState(false); | ||||||
|  |   const [alertMsg, setAlertMsg] = useState(''); | ||||||
|  |   const NativeTestMethod = useMemo(() => { | ||||||
|  |     return [ | ||||||
|  |       { | ||||||
|  |         name: 'setLocalHashInfo', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText( | ||||||
|  |             `setLocalHashInfo\n${Hash}\n{\"version\":\"1.0.0\",\"size\":\"19M\"}`, | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'getLocalHashInfo', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText(`getLocalHashInfo\n${Hash}`); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'setUuid', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText(`setUuid\n${UUID}`); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'reloadUpdate', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText('reloadUpdate'); | ||||||
|  |           setOptions({hash: Hash}); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'setNeedUpdateForApp', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText('setNeedUpdate'); | ||||||
|  |           setOptions({hash: AppPatchHash}); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'setNeedUpdateForPPK', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText('setNeedUpdate'); | ||||||
|  |           setOptions({hash: PPKPatchHash}); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'markSuccess', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText('markSuccess'); | ||||||
|  |           setOptions(undefined); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'downloadPatchFromPpk', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText('downloadPatchFromPpk'); | ||||||
|  |           setOptions({updateUrl: PPKDownloadUrl, hash: PPKPatchHash, originHash: OriginHash}); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'downloadPatchFromPackage', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText('downloadPatchFromPackage'); | ||||||
|  |           setOptions({updateUrl: AppPatchDownloadUrl, hash: AppPatchHash}); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'downloadFullUpdate', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText('downloadFullUpdate'); | ||||||
|  |           setOptions({updateUrl: DownloadUrl, hash: Hash}); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         name: 'downloadAndInstallApk', | ||||||
|  |         invoke: () => { | ||||||
|  |           setText('downloadAndInstallApk'); | ||||||
|  |           setOptions({url: DownloadUrl, target: Hash, hash: Hash}); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     ]; | ||||||
|  |   }, []); | ||||||
|  |  | ||||||
|  |   const renderTestView = useCallback(() => { | ||||||
|  |     const views = []; | ||||||
|  |     for (let i = 0; i < NativeTestMethod.length; i++) { | ||||||
|  |       views.push( | ||||||
|  |         <TouchableOpacity | ||||||
|  |           key={i} | ||||||
|  |           testID={NativeTestMethod[i].name} | ||||||
|  |           onPress={() => { | ||||||
|  |             NativeTestMethod[i].invoke(); | ||||||
|  |           }}> | ||||||
|  |           <Text>{NativeTestMethod[i].name}</Text> | ||||||
|  |         </TouchableOpacity>, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     return <View>{views}</View>; | ||||||
|  |   }, [NativeTestMethod]); | ||||||
|  |   if (!visible) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <SafeAreaView style={{flex: 1, padding: 10}}> | ||||||
|  |       <View | ||||||
|  |         style={{ | ||||||
|  |           flexDirection: 'row', | ||||||
|  |           alignItems: 'center', | ||||||
|  |           justifyContent: 'space-between', | ||||||
|  |           padding: 10, | ||||||
|  |         }}> | ||||||
|  |         <Text>调试Pushy方法(方法名,参数,值换行)</Text> | ||||||
|  |         <Button title="关闭" onPress={() => onClose()} /> | ||||||
|  |       </View> | ||||||
|  |       <TextInput | ||||||
|  |         autoCorrect={false} | ||||||
|  |         autoCapitalize="none" | ||||||
|  |         style={{ | ||||||
|  |           borderWidth: StyleSheet.hairlineWidth * 4, | ||||||
|  |           borderColor: 'black', | ||||||
|  |           height: '30%', | ||||||
|  |           marginTop: 20, | ||||||
|  |           marginBottom: 20, | ||||||
|  |           padding: 10, | ||||||
|  |           fontSize: 20, | ||||||
|  |         }} | ||||||
|  |         textAlignVertical="top" | ||||||
|  |         multiline={true} | ||||||
|  |         value={text} | ||||||
|  |         onChangeText={setText} | ||||||
|  |       /> | ||||||
|  |       {running && <ActivityIndicator />} | ||||||
|  |       <TouchableOpacity | ||||||
|  |         style={{ | ||||||
|  |           backgroundColor: 'rgb(0,140,237)', | ||||||
|  |           justifyContent: 'center', | ||||||
|  |           alignItems: 'center', | ||||||
|  |           paddingTop: 10, | ||||||
|  |           paddingBottom: 10, | ||||||
|  |           marginBottom: 5, | ||||||
|  |         }} | ||||||
|  |         testID="submit" | ||||||
|  |         onPress={async () => { | ||||||
|  |           setRunning(true); | ||||||
|  |           try { | ||||||
|  |             const inputs = text.split('\n'); | ||||||
|  |             const methodName = inputs[0]; | ||||||
|  |             let params = []; | ||||||
|  |             if (inputs.length === 1) { | ||||||
|  |               if (options) { | ||||||
|  |                 await PushyModule[methodName](options); | ||||||
|  |               } else { | ||||||
|  |                 await PushyModule[methodName](); | ||||||
|  |               } | ||||||
|  |             } else { | ||||||
|  |               if (inputs.length === 2) { | ||||||
|  |                 params = [inputs[1]]; | ||||||
|  |               } else { | ||||||
|  |                 params = [inputs[1], inputs[2]]; | ||||||
|  |                 console.log({inputs, params}); | ||||||
|  |               } | ||||||
|  |               await PushyModule[methodName](...params); | ||||||
|  |             } | ||||||
|  |             setAlertVisible(true); | ||||||
|  |             setAlertMsg('done'); | ||||||
|  |           } catch (e) { | ||||||
|  |             setAlertVisible(true); | ||||||
|  |             setAlertMsg(e.message); | ||||||
|  |           } | ||||||
|  |           setRunning(false); | ||||||
|  |         }}> | ||||||
|  |         <Text style={{color: 'white'}}>执行</Text> | ||||||
|  |       </TouchableOpacity> | ||||||
|  |       <Button title="重置" onPress={() => setText('')} /> | ||||||
|  |       {renderTestView()} | ||||||
|  |       <CustomDialog | ||||||
|  |         title={alertMsg} | ||||||
|  |         visible={alertVisible} | ||||||
|  |         onConfirm={() => { | ||||||
|  |           setAlertVisible(false); | ||||||
|  |         }} | ||||||
|  |       /> | ||||||
|  |     </SafeAreaView> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const styles = StyleSheet.create({ | ||||||
|  |   container: { | ||||||
|  |     flex: 1, | ||||||
|  |     justifyContent: 'center', | ||||||
|  |     alignItems: 'center', | ||||||
|  |   }, | ||||||
|  |   overlay: { | ||||||
|  |     position: 'absolute', | ||||||
|  |     top: 0, | ||||||
|  |     left: 0, | ||||||
|  |     right: 0, | ||||||
|  |     bottom: 0, | ||||||
|  |     backgroundColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|  |     justifyContent: 'center', | ||||||
|  |     alignItems: 'center', | ||||||
|  |   }, | ||||||
|  |   dialog: { | ||||||
|  |     backgroundColor: 'white', | ||||||
|  |     borderRadius: 10, | ||||||
|  |     padding: 20, | ||||||
|  |     width: '80%', | ||||||
|  |     alignItems: 'center', | ||||||
|  |   }, | ||||||
|  |   title: { | ||||||
|  |     fontSize: 18, | ||||||
|  |     fontWeight: 'bold', | ||||||
|  |     marginBottom: 20, | ||||||
|  |   }, | ||||||
|  |   button: { | ||||||
|  |     backgroundColor: '#2196F3', | ||||||
|  |     borderRadius: 5, | ||||||
|  |     paddingVertical: 10, | ||||||
|  |     paddingHorizontal: 20, | ||||||
|  |   }, | ||||||
|  |   buttonText: { | ||||||
|  |     color: 'white', | ||||||
|  |     fontWeight: 'bold', | ||||||
|  |   }, | ||||||
|  | }); | ||||||
							
								
								
									
										29
									
								
								Example/expoUsePushy/app.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,29 @@ | |||||||
|  | { | ||||||
|  |   "expo": { | ||||||
|  |     "name": "expoUsePushy", | ||||||
|  |     "slug": "expoUsePushy", | ||||||
|  |     "version": "1.0.0", | ||||||
|  |     "orientation": "portrait", | ||||||
|  |     "icon": "./assets/icon.png", | ||||||
|  |     "userInterfaceStyle": "light", | ||||||
|  |     "newArchEnabled": true, | ||||||
|  |     "splash": { | ||||||
|  |       "image": "./assets/splash-icon.png", | ||||||
|  |       "resizeMode": "contain", | ||||||
|  |       "backgroundColor": "#ffffff" | ||||||
|  |     }, | ||||||
|  |     "ios": { | ||||||
|  |       "supportsTablet": true, | ||||||
|  |       "bundleIdentifier": "com.anonymous.expoUsePushy" | ||||||
|  |     }, | ||||||
|  |     "android": { | ||||||
|  |       "adaptiveIcon": { | ||||||
|  |         "foregroundImage": "./assets/adaptive-icon.png", | ||||||
|  |         "backgroundColor": "#ffffff" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "web": { | ||||||
|  |       "favicon": "./assets/favicon.png" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								Example/expoUsePushy/assets/adaptive-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 17 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Example/expoUsePushy/assets/favicon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Example/expoUsePushy/assets/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 22 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Example/expoUsePushy/assets/shezhi.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 696 B | 
							
								
								
									
										
											BIN
										
									
								
								Example/expoUsePushy/assets/shezhi@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Example/expoUsePushy/assets/shezhi@3x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Example/expoUsePushy/assets/splash-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 17 KiB | 
							
								
								
									
										8
									
								
								Example/expoUsePushy/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | |||||||
|  | import { registerRootComponent } from 'expo'; | ||||||
|  |  | ||||||
|  | import App from './App'; | ||||||
|  |  | ||||||
|  | // registerRootComponent calls AppRegistry.registerComponent('main', () => App); | ||||||
|  | // It also ensures that whether you load the app in Expo Go or in a native build, | ||||||
|  | // the environment is set up appropriately | ||||||
|  | registerRootComponent(App); | ||||||
							
								
								
									
										24
									
								
								Example/expoUsePushy/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,24 @@ | |||||||
|  | { | ||||||
|  |   "name": "expousepushy", | ||||||
|  |   "version": "1.0.0", | ||||||
|  |   "main": "index.js", | ||||||
|  |   "scripts": { | ||||||
|  |     "start": "expo start", | ||||||
|  |     "android": "expo run:android", | ||||||
|  |     "ios": "expo run:ios", | ||||||
|  |     "web": "expo start --web" | ||||||
|  |   }, | ||||||
|  |   "dependencies": { | ||||||
|  |     "expo": "~52.0.46", | ||||||
|  |     "expo-status-bar": "~2.0.1", | ||||||
|  |     "react": "18.3.1", | ||||||
|  |     "react-native": "0.76.9", | ||||||
|  |     "react-native-update": "^10.28.5" | ||||||
|  |   }, | ||||||
|  |   "devDependencies": { | ||||||
|  |     "@babel/core": "^7.25.2", | ||||||
|  |     "@types/react": "~18.3.12", | ||||||
|  |     "typescript": "^5.3.3" | ||||||
|  |   }, | ||||||
|  |   "private": true | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								Example/expoUsePushy/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | |||||||
|  | { | ||||||
|  |   "extends": "expo/tsconfig.base", | ||||||
|  |   "compilerOptions": { | ||||||
|  |     "strict": true | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								Example/expoUsePushy/update.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,14 @@ | |||||||
|  | { | ||||||
|  |   "ios": { | ||||||
|  |     "appId": 29439, | ||||||
|  |     "appKey": "jNA71vpFHTDpEqeZd9yx87zj" | ||||||
|  |   }, | ||||||
|  |   "android": { | ||||||
|  |     "appId": 29413, | ||||||
|  |     "appKey": "vdZWPXU6eyaPE6Avk96-YvwK" | ||||||
|  |   }, | ||||||
|  |   "harmony": { | ||||||
|  |     "appId": 29140, | ||||||
|  |     "appKey": "JLklGflGIRbY-cMebjQwm1J1" | ||||||
|  |   } | ||||||
|  | } | ||||||
 波仔糕
					波仔糕