ウィーチャットで写真を撮られるとページが更新されるバグに苦しめられて気が狂う


長い間調べても、結果はなく、黙って我慢して、苦しんでいるしかない.微信を呼び出す
wx.chooseImage
wx.getLocalImgData
wx.uploadImage
何だかページが更新され、アップロードされた画像が失われます.この明らかなバグは、微信の公衆番号が撮影されると、現在のページにリダイレクトする確率があります(現在のページがリフレッシュされたり、再ロードされたりします).
その後、Androidデバイスの最下位のバグが原因で、上位で処理できなくなり、すべての微信を呼び出すjssdkにもこの問題が発生することが分かった.
げんしょう
  • は、アップロードコンポーネント(最も簡単なであっても)において、ローカルピクチャを選択したり、システムカメラを呼び出して写真を撮ったりした後、ページをリフレッシュする.この問題は100%再現できないが,確率は低くなく,赤米などの低端アンドロイドで発生する確率が高い.
  • は、システムが所有するブラウザで開く場合に比べて、微信で開く場合にこの問題が頻繁に発生する.
  • は、ローカル画像のアップロードを選択するよりも、システムカメラを呼び出して写真をアップロードする場合にこの問題が頻繁に発生する.
  • 大手2社のウェブサイト(新浪微博、赶集網)を勝手に探して、Androidデバイスでウェブページにアクセスし、画像のアップロードを試みたところ、この問題が発生した.
    検索と調査を経て、この問題の原因は自分が想像していたよりも複雑であることが分かった.これはAndroidオペレーティングシステムの下層設計の欠陥による問題であり、Web開発者にとって、このバグを本当に解決する方法はない.
    この問題は最近始まったのではなく、2013年にAndroid技術チームに報告された(Android issue).しかし、残念なことに、Androidチームは今でもこの問題を直視していない.問題を引き起こす手順は、次のとおりです(説明を容易にするために、Appに埋め込まれたwebviewも「ブラウザ」という言葉で表示されます):
    問題の原因
  • Androidのブラウザでファイルアップロード機能を呼び出すと、Androidシステムは現在のプロセスを「ブラウザ」から「ファイルセレクタ」に切り替え(ユーザーによって選択される新しいプロセスは、ピクチャセレクタ、システムカメラ、または他のプロセスである可能性があります)、ブラウザプロセスはバックグラウンドプロセスになります.
  • Androidオペレーティングシステムの設計上の欠陥により、ブラウザプロセスの保存優先度(システムkillから外されない優先度)は他のすべてのバックグラウンドプロセスと同じであるため、オペレーティングシステムがメモリが不足していると判断した場合、ブラウザの進行は保護されません--残念ながら、ブラウザがメモリを占有するのは一般的に大きいため、だから今回のkill操作はkillがブラウザプロセスを落とすのが簡単です.
  • ユーザーが良い画像を選択してブラウザに戻ると、ブラウザプロセスはもう存在しません.Androidのメカニズムに従って、ブラウザプロセスは回復し、kill以前の状態に回復しようとします.残念ながら、どの状態に回復するかはブラウザによって決まりますが、ブラウザはファイルを選択する前の状態に100%回復することはできません.そのため、エンドユーザーが見ている現象は、ファイルの選択が完了した後、ブラウザがリフレッシュし、どの状態にリフレッシュするかはブラウザによって決まります.
  • この問題について、Androidテクノロジーチームの態度は回避(バグをobsoleteとマーク)である--このバグはOSの下位プロセスの切り替えメカニズムに関連しているため、修復のリスクが高すぎる可能性がある.携帯電話のメモリ容量が大きくなるにつれて、この問題が発生する確率はますます小さくなります.
    問題の原因を理解して、問題のいくつかの特徴付けに対しても合理的な解釈があります:ローエンドのアンドロイドのメモリはもっと小さくて、そのため問題が発生する頻度はもっと高いです;一方、ローカルピクチャを選択するよりも、システムカメラを呼び出すのにかかるメモリが大きい(文字の多いピクチャを撮影する場合、特にそうである)ため、カメラを呼び出す際に問題が頻繁に発生する.ユーザーがすでに多くの他のAppを開いている場合、問題が発生する確率はより大きくなります.
    問題の最適化
    この問題については、Androidの最下位の詳細を変更する必要があります.たとえば、現在のプロセスに関連付けられたバックグラウンドプロセスを定義し、関連するバックグラウンドプロセスに高い優先度を設定します.Androidチームが問題を徹底的に解決する前に、このバグは解けませんでしたが、いくつかのworkaroundが存在します.
  • アップロード操作の前に、ブラウザにシンボル的なクッキー(またはlocalStorageなどのローカルストレージスキーム)を書き、アップロードに成功した後、このフラグビットをクリアします.ページの初期ロード時に、フラグビットが存在するかどうかを判断します.存在する場合、ブラウザプロセスがkill後に再起動されたため、現在のページのロードが発生していることを意味します.このときalertは、メモリが不足していることをユーザーに通知し、他のAppを閉じる必要があるというメッセージを出すことができます.この案は一部のユーザー体験を向上させ、問題の発生を避けることができないとしか言いようがない.また、一部のAndroidバージョンのメモリ最適化の欠陥により、システムメモリがまだ多くの場合にメモリクリーンアップ操作が開始され、alertからのメッセージがユーザーに迷惑をかけます.
  • メインシーンが微信で開かれている場合、微信JSDKの画像アップロードインタフェースを使用して画像のアップロード操作を完了することを試みることができる.私は厳格なテストの比較をしたことがないので、JSDKのインタフェースについて、微信チームは多くのテストと修復作業をしたと信じています(例えば、この文書で述べた問題に対して、外部プロセスに切り替えたり、webviewの回復をより正確にしたりすることを避けたりする)、この案を採用するとこの問題の発生確率は小さいかもしれません.しかし、不利なことに、微信JSDKを呼び出してアップロードした画像は、微信のサーバ上に3日間保存されるため、機密情報をアップロードする必要がある場合には適用されません.
  • 上記の2つのworkaroundに加えて、2つの代替案があります.
  • Native Appを開発します.自分のAppプロセスがメモリクリーンアップでkillに落ちた後、リカバリフェーズがどのように回復するかについては、開発者がより多くのことをすることができます.
  • 限定で配信されているwebサービスでサポートされている携帯電話の範囲は、iPhoneやメモリが多い中・ハイエンドのAndroidモデル
  • です.
    残念なことに、この問題には良い解決策がなく、既存のworkaroundはプライバシーに問題があるか(どれだけ改善されるか分からない)、基本的には何の役にも立たない.Webプロジェクトの開発ができるのは、デザイン上の画像のアップロード操作を最小限に抑えるしかない.
    以下はEXTの画像をアップロードする方法で、完全に切り取って、記録と参考にします.
     onTap: function(e) {
        	var me = this;
        	//      
        	if(me.config.type == 'single'){
        		if(me.config.src.indexOf ('common/xiangji.png') > -1
        				|| me.config.src.indexOf ('common/shenfenzheng.png') > -1
        				|| me.config.src.indexOf ('common/yinhangka.png') > -1
        				|| me.config.src.indexOf ('/fileupload/display/') > -1){
        			//    
        			var mesrc = me.config.src;
        			wx.chooseImage({
        			    count: 1, //   9
        			    sizeType: ['compressed'], //             ,      ,      
        			    sourceType: ['camera'], //              ,      
        			    success: function (res) {
        			    	var localIds = res.localIds;
        			    	var id = localIds[0].toString();
        					if(window.__wxjs_is_wkwebview){
        				    	wx.getLocalImgData({
        				    	    localId: id, //    localID
        				    	    success: function (res) {
        				    	        var localData = res.localData; // localData    base64  ,   img    
        				    	        localData = localData.replace('jgp', 'jpeg');
        				    			me.setSrc(localData);
        		    	    			me.config.src = localData;
        				    	    }
        				    	});
        					}else{
        						me.config.src = id;
        						me.setSrc(id);
        				    	if (id.indexOf("wxlocalresource") != -1) {
        				    		id = id.replace("wxlocalresource", "wxLocalResource");
        		                }
        					}
        					//    
        					setTimeout(function(){
        						wx.uploadImage({
            					    localId: id,
            					    isShowProgressTips: 1, //    1,      
            					    success: function (res) {
            					    	var fmMediaId = res.serverId; //               ID
            					    	me.parent.query('input[type="hidden"]')[0].setValue(fmMediaId);
            					    	me.config.mediaId = fmMediaId
            					    	
            					    	if( mesrc.indexOf ('common/shenfenzheng.png') > -1
            				    				|| mesrc.indexOf ('common/yinhangka.png') > -1){
            					    		var parentWidth = me.parent.el.dom.offsetWidth;
            					    		var meWidth = me.el.dom.offsetWidth;
            					    		var left = (parentWidth-meWidth)/2;
            					    		var button = Ext.create('Ext.Button', {
                								height:28,
                				    			width:meWidth,
                				    			left:left,
                				    			style:'background: #000;border-radius: 0;opacity: 0.7;color: #fff;font-size: 1.4rem;letter-spacing: 6px;text-indent: 6px;',
                								text:'  ',
                								bottom:0,
                								listeners:{
                						        	tap: function(){
                							    		this.parent.remove(this);
                							    		me.setSrc(mesrc);
                							    		me.config.src = mesrc;
                							    		me.parent.query('input[type="hidden"]')[0].setValue('');
                						        	}
                						        }
            	    			    	    });
            					    		me.parent.add(button);
            					    	} else {
            					    		var button = Ext.create('Ext.Button', {
                								height:28,
                				    			width:105,
                				    			style:'background: #000;border-radius: 0;opacity: 0.7;color: #fff;font-size: 1.4rem;letter-spacing: 6px;text-indent: 6px;',
                								text:'  ',
                								bottom:0,
                								listeners:{
                						        	tap: function(){
                							    		this.parent.remove(this);
                							    		me.setSrc('./resources/common/xiangji.png');
                							    		me.config.src = './resources/common/xiangji.png';
                							    		me.parent.query('input[type="hidden"]')[0].setValue('');
                						        	}
                						        }
            	    			    	    });
            					    		me.parent.add(button);
            					    	}
        	    			    		
            					    }
            					});
        		    		},100);
        			    }
        			});
        		}else{
            		var srcList = [];
            		srcList.push(me.config.src);
        			//    
        			wx.previewImage({
        			    current: me.config.src, //        http  
        			    urls: srcList//        http    
        			});
        		}
        	}
        	//      
        	else if(this.config.type == 'multiple'){
        		//      3   
                if(EU.isEmpty(me.config.max)) {
                	me.config.max = 3;
        		}
                
        		var objHidden = me.parent.parent.query('input[type="hidden"]')[0];
    	    	if(me.config.src.indexOf ('common/xiangji.png') > -1){
    	    		//    
    	    		wx.chooseImage({
    				    count: 1, //   9
    				    sizeType: ['compressed'], //             ,      ,      
    				    sourceType: ['camera'], //              ,      
    				    success: function (res) {
    				    	var localIds = res.localIds;
    				    	var id = localIds[0].toString();
    		    			me.config.src = id;
    						if(window.__wxjs_is_wkwebview){
    					    	wx.getLocalImgData({
    					    	    localId: id, //    localID
    					    	    success: function (res) {
    					    	        var localData = res.localData; // localData    base64  ,   img    
    					    	        localData = localData.replace('jgp', 'jpeg');
    					    			me.setSrc(localData);
    					    	    }
    					    	});
    						}else{
    							me.setSrc(id);
    					    	if (id.indexOf("wxlocalresource") != -1) {
    					    		id = id.replace("wxlocalresource", "wxLocalResource");
    			                }
    						}
    						//    
    						setTimeout(function(){
    							wx.uploadImage({
    							    localId: id,
    							    isShowProgressTips: 1, //    1,      
    							    success: function (res) {
    							    	var fmMediaId = res.serverId; //               ID
    						    		me.config.mediaId = fmMediaId;
    						    		var mediaId = objHidden.getValue();
    						    		if(EU.isEmpty(mediaId)){
    						    			objHidden.setValue(fmMediaId);
    						    		}else{
    						    			objHidden.setValue(mediaId + ',' + fmMediaId);
    						    		}
    						    		var button = Ext.create('Ext.Button', {
    										height:28,
    										width:'100%',
    						    			style:'background: #000;border-radius: 0;opacity: 0.7;color: #fff;font-size: 1.4rem;letter-spacing: 6px;text-indent: 6px;',
    										text:'  ',
    										bottom:0,
    										listeners:{
    								        	tap: function(){
    									    		var mediaId = objHidden.getValue();
    									    		if(mediaId.substring(mediaId.length-1,mediaId.length) !== ','){
    									    			mediaId = mediaId + ',';
    									    		}
    									    		var ouccerMediaId = me.config.mediaId;
    									    		mediaId = mediaId.replace(ouccerMediaId + ',','');
    									    		objHidden.setValue(mediaId);
    									    		me.config.src = './resources/common/xiangji.png';
    									    		this.parent.destroy();
    								        	}
    								        }
    								    });
    						    		me.parent.add(button);
    						    		if(me.config.max>objHidden.getValue().split(",").length){
    						    			var container = Ext.create('Ext.Container', {
    											width:'30%',
    											margin:'0 10px 10px 0',
    											style:'float:left',
    											items:[]
    							    	    });
    							    		var image = Ext.create('PlusApp.ux.ImgPhoto', {
    							    			height:105,
    											width:'100%',
    											style:'float:left;border-radius: 2px;background-size: cover;',
    											type:'multiple',
    								        	cls:'imgGroup',
    											src: './resources/common/xiangji.png'
    							    	    });
    							    		container.add(image);
    							    		me.parent.parent.add(container);
    						    		}
    							    }
    							});
        		    		},100);
    				    	
    				    }
    				});
    	    	}else{
    	    		var srcList = [];
    	    		var imgGroup = Ext.query('.imgGroup');
    				for (var i = 0; i < imgGroup.length; i++) {
    					var imgSrc = imgGroup[i].style.backgroundImage;
    					if(imgSrc.indexOf('weixin') > -1){
    						imgSrc = imgSrc.substring(imgSrc.indexOf('weixin'),imgSrc.indexOf('")'));
    						srcList.push(imgSrc);
    					}
    				}
        			//    
        			wx.previewImage({
        			    current: me.config.src, //        http  
        			    urls: srcList//        http    
        			});
        		}
    	    }
        }
     
    参考学習:https://blog.csdn.net/dobuy/article/details/87949273
    参考学習:http://blog.shaochuancs.com/android-upload-page-refresh/