0%

objectives orientation:

  • what & what benefits, defect(缺点)
  • 交互interact
  • 隐私和权限
  • 工具链

what is Expo

Expo 是一个基于 React Native 的框架。其服务于简化和便于 React Native 开发方式,Expo框架包括Expo CLI(如 create-expo-app)Expo SDK (其封装了一些导航、设备、通知等功能和api)Expo Go(一个可以在 iOS 和 Android 上安装的应用程序,允许你通过扫描 QR 码或 URL 来即时预览和测试你的 Expo 项目,而不需要构建 APK 或 IPA 文件。)EAS (远程构建 一键推送Google Play和Apple Store)
参考使用Expo开发应用

缺点是对深度定制开发(甚至无法对接支付宝和微信支付功能)和涉及到原生模块的开发缺乏灵活性,需要Expo eject成纯React Native项目,此操作不可逆

安装Expo:

1
2
3
4
5
npx create-expo-app StickerSmash --template blank-typescript
cd StickerSmash

npx expo run:android
npx expo start

使用npx expo install而不是npm i或yarn add,以便提供兼容性提示

Expo路由

file-based router

配置

app.json 存放编译所需静态参数 如app名称、版本信息、OTA配置等
如需动态配置应使用app.config.ts

1
2
3
4
5
6
7
8
import { ExpoConfig, ConfigContext } from 'expo/config';

export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
slug: 'my-app',
name: 'My App',
});

Expo SDK库

EAS

Expo Application Service, 构建安装包需要用eas服务,这是对墙内用户不友好的地方之一

1
2
3
npm i -g eas-cli
eas login
eas build --platform android --profile release

默认打包成abb文件,生成apk需要在eas.json中某个profile中设置好类型如
1
2
3
4
5
"release": {
"android": {
"buildType": "apk"
}
}

树是具有分层数据功能的抽象模型,前端中常见的应用场景如Dom树,级联菜单,treeview控件等

Promise的调用形如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function asyncFunc(data){
return new Promise((resolve, reject)=>{
execute(data)
if(flag) {
resolve(res)
}else{
reject(err)
}
})
}
asyncFunc(data)
.then(res=>{return asyncFunc(res.data)}, err=>{console.log("step1 error")})
.then(res=>{return asyncFunc(res.data)}, err=>{console.log("step2 error")})
.then(res=>{return asyncFunc(res.data)}, err=>{console.log("step3 error")})
.catch(err=>{console.log("mission defeated")})

Promise意在解决异步函数嵌套时产生的回调地狱,使得异步操作可控以及可组合

  • MyPromise应该是一个构造函数,参数是以两个回调方法为形参的函数体 函数体内执行若干异步操作,根据异步状态选择执行上述回调方法
  • MyPromise内部须有一个state 待定(pending)成功(fulfilled)/失败(rejected)
  • 从asyncFunc定义可知resolve,reject用于改变state状态(state后不再改变)而且分别将参数result赋给onFulfilled,参数error赋给onRejected回调. 注意onFulfilled、onRejected是then的两个参数(函数调用的实参)并不是resolve、reject
  • 成员函数then函数根据state状态,成功则执行onFulfilled回调,失败则执行onRejected回调
  • then返回另一个MyPromise(从而可进行链式调用) 新的MyPromise中的异步操作将成为等待前面的onFulfilled、onRejected执行结果, 如何resolve/reject由onFulfilled、onRejected的函数体控制以此类推
  • catch与then类似 只注册失败的回调函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    class MyPromise{
    state = 'pending'
    result = undefined
    error = undefined
    constructor(executor){
    const resolve = {
    if(this.state === 'pending'){
    this.state = 'fulfilled'
    }
    }
    const reject = {
    if(this.state === 'pending'){
    this.state = 'rejected'
    }
    }
    executor(resolve, reject)
    }
    function then(onFulfilled, onRejected){
    return new MyPromise((resolve, reject)=>{
    if(this.state === 'fulfilled'){
    const result = onFulfilled(this.result)
    resolve(result)
    }
    if(this.state === 'rejected'){
    const error = onRejected(this.error)
    reject(error)
    }
    })
    }
    function catch(onRejected){
    return this.then(null, onRejected);
    }
    }
    注意:代码尚缺少形参类型判断及异常处理(try catch throw) 且Promise还有其他API如resolve all finally…

精进参考-> 掘金:你能手写一个Promise吗

如何获取promise多个then之后的值

几何图形渲染到有限分辨率的屏幕上 将图形划成其最小组成部分————片元 对于显示器 就是RGB像素点

判断点是否在三角形内部

顺序边向量叉乘同号

RoadMap

  • 编程基础:C++, 设计模式 —> C++ STL
  • 图形管线:WebGL —> OpenGL
  • 项目实践:闫令琪GAMES101 GAMES202 GAME104 TA百人计划

仿射变换和齐次坐标

仿射变换:位移 缩放 旋转 错切(单一方向等比例缩放)

仿射变换前后保持一致的“平直行” 即直线变换后仍然为直线 相互平行的关系变换后仍然平行

齐次坐标是解决仿射变换中“平移无法用矩阵乘法表示”这一问题的关键。

在二维空间中,一个笛卡尔坐标点 $(x, y)$ 对应的齐次坐标是一个三元组 $(x, y, 1)$

使用齐次坐标的二维变换矩阵
现在,所有变换都可以表示为 $3 \times 3$ 矩阵:

  • 平移:
  • 缩放:
  • 旋转:
  • 组合变换:
    变换的顺序至关重要(通常不满足交换律)。例如,先缩放后旋转,与先旋转后缩放结果不同。
    要表示“先变换 $A$,再变换 $B$”,最终的变换矩阵为 $M = B \cdot A$。
    例如,绕一个任意点 $(c_x, c_y)$ 旋转:
    1. 平移至原点: $T(-c_x, -c_y)$
    2. 绕原点旋转: $R(\theta)$
    3. 平移回去: $T(c_x, c_y)$
      总变换矩阵 $M = T(c_x, c_y) \cdot R(\theta) \cdot T(-c_x, -c_y)$。

三维仿射变换

笛卡尔坐标点 $(x, y, z)$ 的齐次坐标为 $(x, y, z, 1)$

主要的三维仿射变换矩阵

所有变换都由一个 $4 \times 4$ 的矩阵表示。

平移

沿 $x, y, z$ 轴分别移动 $t_x, t_y, t_z$。

缩放

在 $x, y, z$ 轴方向分别缩放 $s_x, s_y, s_z$。

3.2.3 旋转

旋转比二维复杂,因为需要指定旋转轴。我们使用右手坐标系。

  • 绕 X 轴旋转 $\theta$ (Pitch):
  • 绕 Y 轴旋转 $\theta$ (Yaw):
  • 绕 Z 轴旋转 $\theta$ (Roll):

    组合变换

    与二维相同,组合变换通过矩阵乘法实现,且顺序至关重要。例如,一个常见的场景相机的视图变换可以表示为 T * R * S 的形式,具体取决于实现方式。
  • camera: position lookat lookup
  • 视图变换 camera移动至原点 绕轴旋转 反向位移

  • 透视投影(锥形视场 近大远小) 正交投影(相机无限远 远近投影一致)

旋转矩阵的转置即逆矩阵,这种矩阵为正交矩阵

在学习React Native时想到的微信小程序
特点:

  • 自带的传播属性 依托微信分享 二维码分享
  • 体量小 使用方便 跨平台
  • 开发成本低 WXML + WXSS + js

其性能逊色与React Native应用 而且只支持有限的原生API,React Native不是单纯的web应用(Hybrid),可以依托C++ Jave开发原生功能模块,以及优化运算性能等。缘于微信平台限制,微信小程序拥有有限的文件访问权限,有限的websocket实时通信功能,React Native还可以开发离线推送 APNs(Apple Push Notification Service)和 FCM(Firebase Cloud Messaging)微信小程序的推送需要通过订阅号间接实现

更适合React Native的开发场景

  • 高性能动画和图形处理
  • 高性能计算和数据处理
  • 深度集成原生功能
  • 实时通信和推送通知
  • 文件系统和数据库操作
  • 第三方库和工具的集成

1
npm i react-native-vision-camera

camera 和 microphone 权限

AndroidManifest.xml中声明该App需要camera 和 microphone 权限:

1
2
3
4
<uses-permission android:name="android.permission.CAMERA" />

<!-- optionally, if you want to record audio: -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

查询权限
1
2
3
4
5
6
const cameraPermission = Camera.getCameraPermissionStatus()
const microphonePermission = Camera.getMicrophonePermissionStatus()

const showPermissionsPage = cameraPermission !== 'granted' || microphonePermission === 'not-determined'
// 未授权则跳转到 PermissionsPage
props.navigation.navigate(showPermissionsPage?'PermissionsPage':'CameraPage')

getXXXPermissionStatus的结果:

  • granted 授权使用
  • not-determined 尚未申请
  • denied 拒绝(可以再次申请)
  • restricted 禁用

PermissionsPage 请求权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const [cameraPermissionStatus, setCameraPermissionStatus] = useState('not-determined')
const [microphonePermissionStatus, setMicrophonePermissionStatus] = useState('not-determined')

useEffect(()=>{
if(cameraPermissionStatus === 'granted' && microphonePermissionStatus === 'granted'){
navigation.replace('CameraPage')
}

}, [cameraPermissionStatus, microphonePermissionStatus])

const requestPermissions = useCallback(async ()=>{
const cameraPermission = await Camera.requestCameraPermission()
if(cameraPermission === 'denied') await Linking.openSettings() // 设备设置页
setCameraPermissionStatus(cameraPermission)

// ...
})

return (<Text onPress={requestPermissions}>grant</Text>)

Camera视图

1
2
3
4
5
6
7
8
9
10
11
12
const device = useCameraDevice('back')
const { hasPermission } = useCameraPermission()

if (!hasPermission) return <PermissionsPage />
if (device == null) return <NoCameraDeviceError />
return (
<Camera
style={StyleSheet.absoluteFill}
device={device}
isActive={true}
/>
)

设备devices

1
2
const devices = Camera.getAvailableCameraDevices()
const device = getCameraDevice(devices, 'back')

其他针对多摄像头和外部摄像头的选择

isActive可用于暂停会话(pause the session: isActive={false}) 相比于unmount可以更快速再次调用

生命周期
onInitialized — onStarted — onPreviewStarted — onPreviewStopped — onStopped、

格式

1
2
3
4
const format = getCameraFormat(device, [
{ videoResolution: 'max' },
{ photoResolution: 'max' }
])

other format settings

Preview预览

1
2
3
4
5
6
7
8
9
10
11
const camera = useRef<Camera>(null)
...
return(
<Camera {...props}
ref={camera}
photo={true} {/* enable take photo */}
preview={isPausePreview}
onPreviewStarted={() => console.log('Preview started!')}
onPreviewStopped={() => console.log('Preview stopped!')}
androidPreviewViewType="texture-view" />
)

拍照
1
2
3
4
const file = await camera.current.takePhoto()
await CameraRoll.save(`file://${file.path}`, {
type: 'photo',
})

  • RN和Ionic是相似的,基于js/ts的UI桥接原生组件 而Flutter(Dart语言)使用自己的渲染引擎

  • 发布到ios需要ios系统

20250106 Apple Store Top Paid App:

  • 75 Hard 自律
  • hotschedules 员工排班考勤,可能是国外版钉钉
  • Procreate Pocket 绘图动画 图像处理
  • Paprika Recipe Manager 3 菜谱

“生活不会在你都准备好了以后才开始”。面试也一样,面试考验的不是那几轮的面试表现,而是你在长期生活、工作中积累的硬技能和软技能
这些包括:你的专业能力,框架能力,思维能力,性格和心态,沟通能力,价值观等等。你只是刚好在这几轮的面试里表现出了你的这些积累,吸引到了对方,最后拿到了Offer。如果临时抱佛脚,光背概念和知识点,没有结合项目深入思考,那么面试的时候会表现的很空洞,给人的印象只是在堆砌一些关键词,这样面试挂掉的可能性就很高。
———— Keraun https://zhuanlan.zhihu.com/p/145079928

“费曼学习法”

  • “有结果检验的导向 + 功利 + 逻辑”
  • “现学现卖,消化最快”:刚学的知识教别人,消化最快
  • “即时反馈”:学习可以达到即时反馈,这是游戏引人入胜的原理之一
  • “简洁”:简洁不是真相的表现形式,而是真相本身

Remote Procedure Call 远程过程调用