2020年7月

我们在使用 function base component 的时候可以使用 useParams 来获取参数, 类似这样:

const { id } = useParams()

当我们使用 class base component 的时候该如何写好类型呢?

先说结论

import { RouteComponentProps } from 'react-router';

// example route
<Route path="/products/:name" component={ProductContainer} />

interface MatchParams {
    name: string;
}

interface Props extends RouteComponentProps<MatchParams> {
}

查看源代码

// from typings
export interface RouteComponentProps<P> {
  match: match<P>;
  location: H.Location;
  history: H.History;
  staticContext?: any;
}

export interface match<P> {
  params: P;
  isExact: boolean;
  path: string;
  url: string;
}

当我们升级 package.json 包后,容易出现下面的错误:

npm WARN [email protected] requires a peer of [email protected]>= 4.12.1 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of @typescript-eslint/[email protected] but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of @typescript-eslint/[email protected] but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected] but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected] but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^5.0.0 || ^6.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]>=6.1.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected] - 6.x but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^3 || ^4 || ^5 || ^6 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^1.8.18 but none is installed. You must install peer dependencies yourself.

audited 2211 packages in 7.724s

69 packages are looking for funding
  run `npm fund` for details

found 4992 low severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details

问题分析

package-lock.json 中锁定的包版本和新的包依赖的版本有冲突,所以 npm 不知道如何处理这些冲突。

解决办法

rm package-lock.json && rm -rf node_modules/ && npm install

注意⚠️

任何版本升级都可能产生新的问题,建议充分测试后才能上线运行

版本信息

react native: 0.62.2
react-native-apk-manager: ^1.1.0

错误摘要

java.lang.RuntimeException: Package manager has died at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:156)

错误信息

java.lang.RuntimeException: Package manager has died
    at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:139)
    at com.superhao.react_native_apk_manager.ApkManagerModule.isAppInstalled(ApkManagerModule.java:210)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
    at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:151)
    at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
    at android.os.Looper.loop(Looper.java:148)
    at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:226)
    at java.lang.Thread.run(Thread.java:818)
Caused by: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:503)
    at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:2272)
    at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:134)
    ... 11 more
android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:503)
    at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:2272)
    at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:134)
    at com.superhao.react_native_apk_manager.ApkManagerModule.isAppInstalled(ApkManagerModule.java:210)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
    at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:151)
    at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
    at android.os.Looper.loop(Looper.java:148)
    at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:226)
    at java.lang.Thread.run(Thread.java:818)

设备分布

image

问题解决

re: https://github.com/1556173267/react-native-apk-manager/issues/6

  1. 需要避免同时多个线程调用 getPackageInfo,这样容易导致内存溢出 (主要解决方案)
  2. 避免获取过多 package 信息,如下所示
pm.getPackageInfo("com.tencent.mm", PackageManager.GET_ACTIVITIES);
// 修改为 👇
pm.getApplicationInfo("com.tencent.mm", PackageManager.GET_META_DATA);

参考文档

Android 获取 PackageInfo 引发 Crash 填坑
Package Manager Died
Android Package manager has died with TransactionTooLargeException
分析 Package manager has died

最近遇到了很多停更的 github 仓库,作者已明显放弃了维护。当我们需要修改软件包源代码的时候,就麻烦了。如果自己 fork 后发布重新发布新包,维护成本比较高。对于这种情况,更高效的办法是通过打 patch 的方式来修正软件包的代码。

下面介绍一下具体的实现办法:

为单个文件生成补丁

复制源文件,并修改复制后的文件内容,然后运行 diff 命令:

diff -up path/to/source.ext path/to/source.copy.ext > filename.patch

这条命令会产生类似如下的输出, 你将它重定向到一个文件中, 这个文件就是patch.

patch.png

参数详解:
-u 显示有差异行的前后几行(上下文), 默认是前后各3行, 这样, patch中带有更多的信息
-p 显示代码所在的c函数的信息

为多个文件生成补丁

diff -uprN path/to/source/ path/to/source_copy/ > patch

这条命令对比了 path/to/source/ 和 path/to/source_copy/ 两个目录下的所有源码差异.

参数详解:

-r 递归地对比一个目录和它的所有子目录(即整个目录树).
-N 如果某个文件缺少了, 就当作是空文件来对比。如果不使用本选项, 当diff发现旧代码或者新代码缺少文件时, 只简单的提示缺少文件。如果使用本选项, 会将新添加的文件全新打印出来作为新增的部分。

打补丁

我们将所有生成的 patch 文件放到 patches 目录后就可以使用脚本批量打补丁了。

#/bin/bash

# patch all file in patches dir
for i in $(find ./patches -name '*.patch');
do
  patch -N -p0 < $i > /dev/null 2>&1 &
done