目录

1、已有可实用的动态 pdf 生成方案,

2、安卓编辑器中建立 Layout ,添加 WebView :

3、extends Activity 将上面的 WebView 赋值给变量(实例化?),并设置其大堆属性,以扩展其功能:

4、引入参考资料 1 的方法,定义下载完成监听器

5、获取 Blob 链接文件名及类型

6、重写 WebView 的下载监听器 DownloadListener 

7、其中的几个变量及其他说明


参考资料

1.Android WebView支持下载blob协议文件_Misdirection_XG的博客-CSDN博客_android blob

2. Android Webview实现文件下载功能 – huidaoli – 博客园

3.base64和Blob互相转换_weixin_30776863的博客-CSDN博客

4.Android:你要的WebView与JS交互方式都在这里了 – 百度文库

用于html转pdf文件下载之最合理的方法支持中文_jessezappy的博客-CSDN博客

项目需求

1.网页动态生成 pdf 文件。

2.手机打开以上网页下载 pdf 文件,并用外部程序打开 pdf 文件。

之前的文章html转pdf文件下载之最合理的方法支持中文_jessezappy的博客-CSDN博客 ,中已经实现网页动态生成 pdf 文件,通过好多种方式都可在 PC 端实现自动下载动态生成的 pdf 文件,如:

pdf.save("A4.pdf") ;

但我项目计划是用手机打开这个网页下载 pdf 的,那些方法到了手机端,用 WebView 打开网页后,均无法下载由网页 js 生成的 pdf 文档

深度研究 jspdf.umd.js 后,发现,其输出 pdf 数据有好多种参数

    /**
     * Generates the PDF document.
     *
     * If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
     *
     * @param {string} type A string identifying one of the possible output types.<br/>
     *                      Possible values are: <br/&gt;
     *                          'arraybuffer' -&gt; (ArrayBuffer)<br/&gt;
     *                          'blob' -&gt; (Blob)<br/&gt;
     *                          'bloburi'/'bloburl' -&gt; (string)<br/&gt;
     *                          'datauristring'/'dataurlstring' -&gt; (string)<br/>
     *                          'datauri'/'dataurl' -> (undefined) -> change location to generated datauristring/dataurlstring<br/>
     *                          'dataurlnewwindow' -> (window | null | undefined) throws error if global isn't a window object(node)<br/>
     *                          'pdfobjectnewwindow' -> (window | null) throws error if global isn't a window object(node)<br/>
     *                          'pdfjsnewwindow' -> (wind | null)
     * @param {Object|string} options An object providing some additional signalling to PDF generator.<br/>
     *                                Possible options are 'filename'.<br/>
     *                                A string can be passed instead of {filename:string} and defaults to 'generated.pdf'
     * @function
     * @instance
     * @returns {string|window|ArrayBuffer|Blob|jsPDF|null|undefined}
     * @memberof jsPDF#
     * @name output
     */


    var output = API.output = API.__private__.output = SAFE(function output(type, options) {
      options = options || {};

      if (typeof options === "string") {
        options = {
          filename: options
        };
      } else {
        options.filename = options.filename || "generated.pdf";
      }

      switch (type) {
        case undefined:
          return buildDocument();

        case "save":
          API.save(options.filename);
          break;

        case "arraybuffer":
          return getArrayBuffer(buildDocument());

        case "blob":
          return getBlob(buildDocument());

        case "bloburi":
        case "bloburl":
          // Developer is responsible of calling revokeObjectURL
          if (typeof globalObject.URL !== "undefined" &amp;&amp; typeof globalObject.URL.createObjectURL === "function") {
            return globalObject.URL &amp;&amp; globalObject.URL.createObjectURL(getBlob(buildDocument())) || void 0;
          } else {
            console.warn("bloburl is not supported by your system, because URL.createObjectURL is not supported by your browser.");
          }

          break;

        case "datauristring":
        case "dataurlstring":
          var dataURI = "";
          var pdfDocument = buildDocument();

          try {
            dataURI = btoa(pdfDocument);
          } catch (e) {
            dataURI = btoa(unescape(encodeURIComponent(pdfDocument)));
          }

          return "data:application/pdf;filename=" + options.filename + ";base64," + dataURI;

        case "pdfobjectnewwindow":
          if (Object.prototype.toString.call(globalObject) === "[object Window]") {
            var pdfObjectUrl = "https://cdnjs.cloudflare.com/ajax/libs/pdfobject/2.1.1/pdfobject.min.js";
            var integrity = ' integrity="sha512-4ze/a9/4jqu+tX9dfOqJYSvyYd5M6qum/3HpCLr+/Jqf0whc37VUbkpNGHR7/8pSnCFw47T1fmIpwBV7UySh3g==" crossorigin="anonymous"';

            if (options.pdfObjectUrl) {
              pdfObjectUrl = options.pdfObjectUrl;
              integrity = "";
            }

            var htmlForNewWindow = "<html>" + '<style>html, body { padding: 0; margin: 0; } iframe { width: 100%; height: 100%; border: 0;}  </style><body><script src="' + pdfObjectUrl + '"' + integrity + '></script><script >PDFObject.embed("' + this.output("dataurlstring") + '", ' + JSON.stringify(options) + ");</script></body></html>";
            var nW = globalObject.open();

            if (nW !== null) {
              nW.document.write(htmlForNewWindow);
            }

            return nW;
          } else {
            throw new Error("The option pdfobjectnewwindow just works in a browser-environment.");
          }

        case "pdfjsnewwindow":
          if (Object.prototype.toString.call(globalObject) === "[object Window]") {
            var pdfJsUrl = options.pdfJsUrl || "./examples/PDF.js/web/viewer.html";
            var htmlForPDFjsNewWindow = "<html>" + "<style>html, body { padding: 0; margin: 0; } iframe { width: 100%; height: 100%; border: 0;}  </style>" + '<body><iframe id="pdfViewer" src="' + pdfJsUrl + "?file=&downloadName=" + options.filename + '" width="500px" height="400px" />' + "</body></html>";
            var PDFjsNewWindow = globalObject.open();
			console.log(htmlForPDFjsNewWindow);
            if (PDFjsNewWindow !== null) {
              PDFjsNewWindow.document.write(htmlForPDFjsNewWindow);
              var scope = this;

              PDFjsNewWindow.document.documentElement.querySelector("#pdfViewer").onload = function () {
                PDFjsNewWindow.document.title = options.filename;
                PDFjsNewWindow.document.documentElement.querySelector("#pdfViewer").contentWindow.PDFViewerApplication.open(scope.output("bloburl"));
              };
            }

            return PDFjsNewWindow;
          } else {
            throw new Error("The option pdfjsnewwindow just works in a browser-environment.");
          }

        case "dataurlnewwindow":
          if (Object.prototype.toString.call(globalObject) === "[object Window]") {
            var htmlForDataURLNewWindow = "<html>" + "<style>html, body { padding: 0; margin: 0; } iframe { width: 100%; height: 100%; border: 0;}  </style>" + "<body>" + '<iframe src="' + this.output("datauristring", options) + '"></iframe>' + "</body></html>";
			
            var dataURLNewWindow = globalObject.open();

            if (dataURLNewWindow !== null) {
              dataURLNewWindow.document.write(htmlForDataURLNewWindow);
              dataURLNewWindow.document.title = options.filename;
            }

            if (dataURLNewWindow || typeof safari === "undefined") return dataURLNewWindow;
          } else {
            throw new Error("The option dataurlnewwindow just works in a browser-environment.");
          }

          break;

        case "datauri":
        case "dataurl":
          return globalObject.document.location.href = this.output("datauristring", options);

        default:
          return null;
      }
    });

以上这些参数,在 CallBack调用 pdf.Output 时使用

var link = document.getElementById('linklink');
link.target = '_blank';
//link.href = window.URL.createObjectURL(convertBase64UrlToBlob(pdf.output('datauristring',{filename: 'A4.pdf'})));//140ms Base64 数据转 Blob
//link.href = window.URL.createObjectURL(pdf.output('blob',{filename: 'A4.pdf'}));//77ms Base64 数据
link.href = pdf.output('bloburi');//77ms 直接输出Blob 链接
//link.href = 
//pdf.output('pdfobjectnewwindow',{filename: 'A41.pdf'});//弹出对象窗口,无用
//link.href = pdf.output('dataurl',{filename: 'A4.pdf'});//数据链接无用				
//pdf.output('pdfjsnewwindow',{filename: 'A42.pdf'});//弹出窗口
//pdf.output('dataurlnewwindow',{filename: 'A43.pdf'});//弹出窗口,无用
link.download ="A41.pdf";				
link.text='点击这里下载';

经过对比,发现在不考虑后台生成 pdf 文件的情况下,只有生成 Blob 链接适合用于手机前台下载,但只有华为自带浏览器支持下载 blob 链接而且还必须用华为浏览器打开那个网页才行,QQ、百度等均不支持下载 blob 链接

jspdf 中原例子里面使用的是 iframe.src = pdf.output(‘datauristring’); 方式返回的是 Base64 编码的 pdf 数据可以使用参考资料 3 中的 convertBase64UrlToBlob 转换为 Blob 链接分析 jspdf 的 Out 方法发现其可直接输出 Blob 链接,那么就暂时用不到参考资料 3 中的方法了。

最终决定,由网页 JS 生成 Blob 链接给 A 标签,在手机端点这个 A 标签下载为 pdf 文档,并打开

(刚刚写了一大段,按了下 Ctrl+z 就全没了,草稿也没了,是要我重新梳理下吗???)

那么,就重新梳理,整理一下解决方法好了,零碎的分析就不写了。

那么,项目解决方案步骤开始:

1、已有可实用的动态 pdf 生成方案,详见:

html转pdf文件下载之最合理的方法支持中文_jessezappy的博客-CSDN博客

2、安卓编辑器中建立 Layout ,添加 WebView :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webfrm"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <WebView
        android:id="@+id/webshow"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true" />
    
</RelativeLayout>

3、extends Activity 将上面的 WebView 赋值变量实例化?),并设置大堆属性,以扩展功能

WebView mWebView;

onCreate 中赋值 mWebView:

mWebView=(WebView)findViewById(R.id.webshow);
setWebStyle();

设置 mWebView 属性重写部分动作扩展功能

@SuppressLint("SetJavaScriptEnabled")
	private void setWebStyle() {  
    	WebSettings  webseting  =  mWebView.getSettings();  
        
        
        webseting.setAppCachePath(getApplicationContext().getCacheDir().getAbsolutePath());
        webseting.setUseWideViewPort(true);
        webseting.setLoadWithOverviewMode(true);
        //webseting.setPluginState(WebSettings.PluginState.ON);        
        webseting.setDomStorageEnabled(true);//最重要的方法,一定要设置,这就是出不来的主要原因  //webseting.setDomStorageEnabled(true);
        
        webseting.setSupportZoom(true);  
        webseting.setDefaultTextEncodingName("utf-8");
        /* 下载blob准备 */        
		webseting.setJavaScriptEnabled(true);
		webseting.setJavaScriptCanOpenWindowsAutomatically(true);

        /***********************/
        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);// 去掉底部右边滚动条
        mWebView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);  // 去掉底部右边滚动条
        
        mWebView.requestFocus();  
      
         webseting.setCacheMode(WebSettings.LOAD_DEFAULT);   // 默认使用缓存 
        // webseting.setCacheMode(WebSettings.LOAD_NO_CACHE); //默认不使用缓存!
         webseting.setAppCacheMaxSize(1024*1024*20);//设置缓冲大小,便于第一次缓存字体,否则每次下载字体需时太长。 
         String  appCacheDir=this.getApplicationContext().getDir("cache",Context.MODE_PRIVATE).getPath();       
                 webseting.setAppCachePath(appCacheDir);   
                 webseting.setAllowFileAccess(true);   
                 webseting.setAppCacheEnabled(true);   
                 webseting.setCacheMode(WebSettings.LOAD_DEFAULT|WebSettings.LOAD_CACHE_ELSE_NETWORK);
          
      //webview 动作重写 
        mWebView.setWebViewClient(new WebViewClient(){
            @Override
			public boolean shouldOverrideUrlLoading(WebView view, String url) {      
                view.loadUrl(url);   
                return false;// false 显示frameset, true 不显示Frameset ,内嵌页面
                //return true;      
            }     
            @Override    
            public void onPageStarted(WebView view, String url, Bitmap favicon) {    
                //有页面跳转时被回调             	
            	//dialog = ProgressDialog.show(webxj.this,null,"数据加载中,请稍侯...");              	
            	super.onPageStarted(view, url,favicon);  
            }              
            @Override
			public void onPageFinished(WebView view, String url) {   
            	//页面跳转结束后被回调  
            	//dialog.dismiss();
                super.onPageFinished(view, url);   
            }   
            @Override    
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {    
            	 super.onReceivedError(view, errorCode, description, failingUrl);//错误处理+ description
                Toast.makeText(webxj.this, "错误:请检查网络链接! " , Toast.LENGTH_SHORT).show();  
                dialog.dismiss(); 
		         new Handler().postDelayed(new Runnable() {  
			            public void run() {  
			            	mWebView.loadUrl(urlw);    //显示等待画面
			            }        
			        }, 500);                 
            }
            
        });  
        //禁用webview右键功能:长按
        mWebView.setOnLongClickListener(new OnLongClickListener(){
        	public boolean onLongClick(View v) {
				// TODO Auto-generated method stub
				return true;
			}
        });

        //blob
        //下载支持,A 标签内需 download
        mWebView.setDownloadListener(new MyWebViewDownLoadListener());    //  设置 WebView 下载监听器  
        mWebView.addJavascriptInterface(mDownloadBlobFileJSInterface, "Android"); // Blob 下载 js 定义
		mDownloadBlobFileJSInterface.setDownloadGifSuccessListener(new openDownloadfile()); // Blob 下载完成监听器
     } 

4、引入参考资料 1 的方法定义下载完成监听器

注:上面步骤 3 中已正确设置下载完成监听器

mDownloadBlobFileJSInterface.setDownloadGifSuccessListener(new openDownloadfile()); //下载完成监听器

参考资料 1 中的:

mDownloadBlobFileJSInterface.setDownloadGifSuccessListener(absolutePath -> Toast.makeText(MainActivity.this,"下载成功,在Download目录下",Toast.LENGTH_SHORT).show());

这句有问题absolutePath 未定义,怀疑其是抄来的代码,没抄全,分析发现其为定义下载完成监听器,那么,就按照重写 DownloadListener 的定义,自己定义一个监听器,用于下载完成后的处理,如调用外部程序打开

/* 定义下载完成事件监听器 */
private class openDownloadfile implements DownloadGifSuccessListener {    	
	public void ondownloadGifSuccess(String gifFile){
		String fileName=gifFile.substring(gifFile.lastIndexOf("/")+1); 
		String directory=gifFile.substring(0,gifFile.lastIndexOf("/")+1);
		// System.out.println("11.下载成功,fileName:"+fileName);
		// System.out.println("12.下载成功,directory:"+directory);
		
        File File = new File(directory,fileName);		
		Intent intent = getFileIntent(File); 
        startActivity(intent); //调用万部程序打开
		// System.out.println("13.下载成功,在Download目录下:"+gifFile);
	}  
}

public Intent getFileIntent(File file){  
//       Uri uri = Uri.parse("http://m.ql18.com.cn/hpf10/1.pdf");  
        Uri uri = Uri.fromFile(file);  
        String type = getMIMEType(file);  
        // Log.e("tag", "type="+type);  
        Intent intent = new Intent("android.intent.action.VIEW");  
        intent.addCategory("android.intent.category.DEFAULT");  
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
        intent.setDataAndType(uri, type);  
        return intent;  
      } 

private String getMIMEType(File f){     
      String type="";    
      String fName=f.getName();    
      // * 取得扩展名 * /    
      String end=fName.substring(fName.lastIndexOf(".")+1,fName.length());//.toLowerCase();
      Locale loc = Locale.getDefault();//可以去掉这步
      end=end.toLowerCase(loc);
      // * 依扩展名类型决定MimeType * /  
      if(end.equals("pdf")){  
          type = "application/pdf";//  
      }  
      else if(end.equals("m4a")||end.equals("mp3")||end.equals("mid")||    
      end.equals("xmf")||end.equals("ogg")||end.equals("wav")){    
        type = "audio/*";     
      }    
      else if(end.equals("3gp")||end.equals("mp4")){    
        type = "video/*";    
      }    
      else if(end.equals("jpg")||end.equals("gif")||end.equals("png")||    
      end.equals("jpeg")||end.equals("bmp")){    
        type = "image/*";    
      }    
      else if(end.equals("apk")){     
        // * android.permission.INSTALL_PACKAGES * /     
        type = "application/vnd.android.package-archive";   
      }  
//      else if(end.equals("pptx")||end.equals("ppt")){  
//        type = "application/vnd.ms-powerpoint";   
//      }else if(end.equals("docx")||end.equals("doc")){  
//        type = "application/vnd.ms-word";  
//      }else if(end.equals("xlsx")||end.equals("xls")){  
//        type = "application/vnd.ms-excel";  
//      }  
      else{  
//        // * 如果无法直接打开,就跳出软件列表用户选择 * /    
        type="*/*"; //因注释多加了一个空格 
      }  
      return type;  
    }  

其中 getFileIntent 和 getMIMEType 来自参考资料 2 。

参考资料 1 中的 DownloadBlobFileJSInterface 可直接使用,等下 获取 Blob 文件名时才需修改转换 Base64 及保存过程

5、获取 Blob 链接文件名类型

参考资料 1 中,是无法取得 Blob 文件名类型的,那么就要用个变通的方法调用网页预设的 JS 中的 getDname 函数获取文件名文件名已事先由 .html 方法回调函数中预设。

<script>	
    // 网页中已由 link.download ="A41.pdf"; 设置文件名
pdf.html(document.getElementById('pdfx'), {	// 只有 addFileToVFS 方法添加的字体才能用于 .html 方法
			callback: function (pdf) {									
				d = new Date();timex=d.getTime();
				var link = document.getElementById('linklink');
				link.target = '_blank';				
				link.href = pdf.output('bloburi');//77ms
				link.download ="A41.pdf";				
				link.text='点击这里下载';
				d = new Date();	
				timex=d.getTime()-timex;
				console.log('总用时'+timex + "ms");
				//link.click();
				//pdf.save("A4.pdf");//自动下载
				//getDname(link.href);
			}
		});

    // 用于 安卓 WebView 调用获取 download 属性的文件名
        function getDname(s){			
			var a=document.getElementsByTagName("a");
			var h="";
			for(let i=0;i<a.length;i++){
				console.log(a[i].href);
				if(a[i].href===s){				
					h=a[i].download;
					i=a.length;
				}
			}
			console.log(h);
			return h;
		}
</script>

6、重写 WebView 的下载监听器 DownloadListener 

注:下载监听器已在 setWebStyle(); 中设置:

mWebView.setDownloadListener(new MyWebViewDownLoadListener());

在下载监听器中判断是否为 Blob 链接,不是则启用参考资料 2 中的直接下载进程

是的话,则启用参考资料 1 中的 Blob 下载进程,并在下载前调用网页中的 getDname js 函数获取预设的 Blob 文件名

    // 改装blob下载 
  private class MyWebViewDownLoadListener implements DownloadListener {    	  
		public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype,long contentLength){  
			if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
				Toast.makeText(webxj.this, "需要SD卡。",  Toast.LENGTH_SHORT).show();
				return;  
			}			
			//Toast.makeText(webxj.this,"Url:"+url.lastIndexOf("data:app"), Toast.LENGTH_SHORT).show();
			// System.out.println("Url:"+url);
			// Log.e("tag", "Url="+url);			
			if(url.indexOf("blob:http")==0){
				urlP=url;
				// System.out.println("打开:"+urlP);
				//mWebView.loadUrl("javascript:calljs();");				
				mWebView.evaluateJavascript("javascript:getDname('"+urlP+"')", new ValueCallback<String>(){
					public void onReceiveValue(String value){						
						// System.out.println("JS返回::"+value);
						pdffn=value.replace(""","");
						// System.out.println("pdffn:"+pdffn);
						File directory= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);  
						File file=new File(directory,pdffn);  
						if(file.exists()){  
							// Log.e("tag", "The file has already exists.");  //文件已存在
							System.out.println("文件已存在:"+directory+pdffn);
							Toast.makeText(webxj.this, "文件已保存:"+directory+"/"+pdffn,Toast.LENGTH_LONG).show();
					        File File = new File(directory,pdffn);		
							Intent intent = getFileIntent(File); 
					        startActivity(intent);
						}else{ 						
							mWebView.loadUrl(DownloadBlobFileJSInterface.getBase64StringFromBlobUrl(urlP));
						}
					}
				});				
	            //mWebView.loadUrl(DownloadBlobFileJSInterface.getBase64StringFromBlobUrl(url));	            			
			}else{
				DownloaderTask task=new DownloaderTask();  
				task.execute(url); 				
			}
		}  
    }

注意:网页 JS 返回的字符串前后双引号包裹需要将其去除。

其中, DownloaderTask参考资料 2 的直接下载方法,注意,A 标签中必须加上 download ,否则报错

<a href="./upload/dll.rar" download>dll.rar</a>

 然后,在 onCreate 打开动态生成 pdf 文件的页面即可

        double rndX=Math.random();
        urlx="?v="+String.valueOf(rndX);
        urlm=getString(R.string.mainUrl);//
        mWebView=(WebView)findViewById(R.id.webshow);        
        setWebStyle();
        mWebView.loadUrl(urlm + urlx);

7、其中的几个变量及其他说明

// 定义于 extends Activity 与 onCreate 之间
	WebView mWebView;    // WebView 实例变量
	private String urlx=new String(""); //存放调用首页参数等,如 double rndX=Math.random();       urlx="?v="+String.valueOf(rndX);

	private String urlw=new String("file:///android_asset/index.html"); //存放等待页面url
	private String urlm;//存放首页菜单页面

	DownloadBlobFileJSInterface mDownloadBlobFileJSInterface = new DownloadBlobFileJSInterface(this);    // Blob 下载 js 接口定义
	private String urlP=new String("");    // 下载链接全局变量
	private static String pdffn=new String("");    // Blob 文件名全局变量

其中 pdffn 用于存放 Blob 链接预设文件名,因为我懒得其动 DownloadBlobFileJSInterface输入变量,就用这个传递给其中的 convertToGifAndProcess 方法,用做保存文件名:

/**
		 * 转换成file
		 * @param base64
		 */
		private void convertToGifAndProcess(String base64) {
			String fileName =pdffn;// UUID.randomUUID().toString() + ".pdf";
			// System.out.println("3.convertToGifAndProcess:fileName:" + fileName);
			File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
			File gifFile = new File(directory, fileName);
			// System.out.println("4.convertToGifAndProcess:gifFile:" + gifFile);
			// Log.e("tag", "type=convertToGifAndProcess" + gifFile);
			saveFileToPath(base64, gifFile);
			// System.out.println("7.convertToGifAndProcess:mDownloadGifSuccessListener:" + mDownloadGifSuccessListener);
			// System.out.println("8.convertToGifAndProcess gifFile:" + gifFile);
			if (mDownloadGifSuccessListener != null) {
				// System.out.println("10.mDownloadGifSuccessListener 不为空到这里:" + mDownloadGifSuccessListener);
				mDownloadGifSuccessListener.ondownloadGifSuccess(gifFile.getAbsolutePath());
			}
		}

		/**
		 * 保存文件
		 * @param base64
		 * @param gifFilePath
		 */
		private void saveFileToPath(String base64, File gifFilePath) {
			// System.out.println("5.saveFileToPath gifFilePath.getAbsolutePath():" + gifFilePath.getAbsolutePath());
			try {
				byte[] fileBytes = Base64.decode(base64.replaceFirst(
					"data:application/pdf;base64,", ""), 0);
				FileOutputStream os = new FileOutputStream(gifFilePath, false);
				os.write(fileBytes);
				os.flush();
				os.close();
				Toast.makeText(mContext, "文件已保存:"+gifFilePath,Toast.LENGTH_LONG).show();
				// Log.e("tag", "type=saveFileToPath" + gifFilePath);
				// System.out.println("6.saveFileToPath FileOutputStream gifFilePath:" + gifFilePath);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}

至此,完整流程及关键代码完成,下面是运行后的样例

 

 

’——————————-

此记!

接下来还要解决下手机端显示宽度问题

原文地址:https://blog.csdn.net/jessezappy/article/details/126264165

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_40008.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注