最近项目快结束了,测试提了一个bug,iOS手机上加载pdf一直在转圈,加载不出来内容。看到这个bug,在电脑上和安卓手机上没有问题,iOS手机中打开确实又问题,初步确定为app问题。我们的项目是集成在客户的app里的,可能是app内的WebView和Safari有一些差异导致的问题。
- 首先直接在iOS手机上用app和Safari分别访问本地启动的项目,发现打开之后一直转圈,但是没有报错信息,因为手机上是用vConsole看的,不确定是不是一些信息被过滤掉了,所以就在电脑上用Safari打开同一个页面,结果和手机上一样,依然没有报错信息。
- 因为没有错误信息,看了一会儿也没有头绪,突然想到之前遇到过,本地项目无法加载一些js,导致页面显示不全,有没有可能因为本地项目导致部分js加载不全,造成pdf加载不出来。尝试在电脑上用Safari打开远程页面,发现可以正常加载,手机上用Safari测试也可以正常加载,所以问题确定为iOS手机的app中无法加载pdf。
- app中无法加载,想到是不是pdf链接又问题,单独复制链接在代码中写死,测试发现也加载不出来。然后想到是不是app内部有网络限制,用app提供的方法ping pdf链接的域名,发现可以正常访问,所以排除链接和网络问题。
- 在github上
react-pdf
库的issues中搜索,发现有一个类似的问题,但是是Cordova的项目,情况应该不一样,所以就略过了。 - 没办法只能看
react-pdf
的源码,发现Document中除了之前用的onLoadSuccess
方法,还有其他的onLoadError
,onSourceSuccess
,onSourceError
方法,加上这些方法,重新打包发布项目后,在app中打开发现,终于看到了一条有用的信息message: “undefined is not an object (evaluating ‘e.body.getReader’)”
,再搜索源码,定位到报错位置是pdfjs
中的PDFFetchStreamReader
类中相关的方法报错,查看相关代码逻辑。传递pdf url后,pdfjs
会请求这个url,拿到返回pdf数据后再去加载,现在是第一步请求pdf url没有返回数据导致报错,所以没有加载pdf。 - 搜索类似问题,发现Pdf.js body.getReader 报错问题,不过有点不同,这个问题是qq浏览器加载问题,不过提供了思路,需要手动请求pdf url,然后把数据内容赋值给
pdfjs
就可以正常加载了。 - 有思路之后,参考步骤4中的请求方法,在Document的
onLoadError
方法中,直接请求pdf url,把请求后的数据赋值给Document,这样就可以正常加载pdf了。onDocumentLoadError = (e) => { console.error('onDocumentLoadError', e); if (typeof this.state.pdfUrl == 'string') { this.transferUrlToArrBuffer(this.state.pdfUrl); } }; transferUrlToArrBuffer = async (url) =>{ const res = await fetch(url); const arrBuffer = await res.arrayBuffer(); this.setState({pdfUrl: arrBuffer}); };
- render中的方法如下,
<Document file={pdfUrl} onl oadSuccess={this.onDocumentLoadSuccess} onl oadError={this.onDocumentLoadError} options={{ cMapUrl: `//cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/cmaps/`, cMapPacked: true, }} > <Page pageNumber={1} onRenderSuccess={this.onLoadSuccess}/> </Document>