본문으로 바로가기
반응형

[Javascript] IOS 웹뷰 뒤로가기 자바스크립트 오류(IOS History Back Error)

 

안녕하세요. 갓대희 입니다. 이번 포스팅은 [ [Javascript] 아이폰 뒤로가기 오류(IOS History Back Error) ] 입니다. : ) 

 

 

0.들어가기 앞서

Safari, Firefox 브라우저에서, 나와 같은 경우 아이폰 웹뷰 Safari의 경우에
BFCache 때문에 페이지 개발 방식에 따라 뒤로가기시 스크립트 로드가 되지 않아 정상 동작하지 않는 경우가 있다.

 

별 의미 없지만 문득, 이런 오류를 겪을수 있는 확률? 가능성?이 얼마나 되는지 확인해 보고 싶었다. 다음 모바일 브라우저의 사용 통계 데이터를 확인해보자.

 

1) 전 세계 기준

 - 크롬이 약 65% 점유율로 단연 앞서며, 사파리가 약 25%로 한 축을 이루고 있다.

뒤이어 삼성 갤럭시의 힘을 받아 삼성 인터넷 브라우저가 뒤를 이어 가고 있는 모습이다.

넷마켓쉐어, 2020년도 1~7월 기준

 

2) 한국 기준

 - 크롬이 약 40% 점유율, 삼성 26%, 사파리가 약 20%로 결국 최소 20% 이상은 Safari를 사용하고 있는 것이다.

스탯카운터, 2020년도 1~7월 기준

 

1. 오류 현상

 -  상기 브라우저(IOS 웹뷰 등)에서 뒤로가기기 자바스크립트가 실행되지 않는 경우.

ex) 뒤로가기시 BFCache로 동작하였기 때문에 네트워크 요청도 없고, Page Load시의 페이지를 만드는 스크립트 동작도 이루어지지 않는 경우.

 

2. BFCach(Back-Forward Cache)

 - 해당 현상의 원인은 BF Cache 때문이다.
   아이폰(IOS) Safari 브라우저에서 뒤로가기(history.back) 또는 동일 페이지 등으로 이동하는 경우 BF Cache를 사용한다.

 

 - BFCache란 동일 세션내 브라우저에서 이전 페이지를 보다 빠르게 로딩하기 위해 이전에 저장한 캐싱된 페이지를 바로 로드하는 방법이라고 할 수 있을것 같다.

참고 : developer.mozilla.org/en-US/docs/Archive/Misc_top_level/Working_with_BFCache

 

 - 장점 : 미리 저장한, 즉 캐싱된 페이지를 그대로 사용하기 때문에 페이지 응답 속도, 즉 속도적인 측면에서 유리하다. 이 캐싱 상태는 브라우저를 닫을 때까지 유지된다.
 - 단점 : window.onload, $(document).ready()와 같은 onLoad 이벤트가 동작하지 않기 때문에 개발자의 의도와 다른 페이지를 보여줄 수 있다.

 

좀더 자세한 내용은 위 참고 url을 확인 해보자.

 

3. 뒤로가기 오류 해결 방안.

 - 다음 가이드에 따라 2가지 가능한 방법을 확인할 수 있었다.

developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/1.5/Using_Firefox_1.5_caching

 

※ 해결 방안

▶ 3.1 pagehide / pageshow 사용, persisted 속성 사용

 - 위 가이드에서 확인해보면 pageshow/pagehide 이벤트를 대안으로 제시하고 있다.
 - 파이어 폭스와 같은 경우 2009년 부로 pagehide / pageshow 이벤트가 생겼고(현재 물론 safari에서도 정상 동작) 해당 이벤트에 대해 알아 보자.

(bugs.webkit.org/show_bug.cgi?id=28758)

 

1) pageshow 함수 : load 이벤트에 대응
2) pagehide 함수 : unload 이벤트에 대응

3) persisted 속성

- window.onpageshow(onpagehide)함수의 event 파라미터에서 event.persisted를 통해 BForward Cache를 이용해서 호출되었을 경우 true, 아닌경우 false를 리턴 한다.

4) window.performance.navigation 객체 사용

- 혹시나 event.persisted가 동작하지 않는 경우를 대비하여 추가 하였다.

- window.performance.navigation 객체는 리다이렉트(redirect), 앞/뒤 버튼, 혹은 보통의 URL 로딩이 어떤 페이지 로드를 일으키는지(trigger) 등의 확인에 사용할 수 있는 속성을 갖고 있다.

 - window.performance.navigation.type = 2 인경우 History 이동을 의미 한다.

 

※ 참고
0(TYPE_NAVIGATENEXT) : 링크 클릭, 직접 입력, Form submit 등의 네비게이션
1(TYPE_RELOAD) : 리로드(reload) 또는 location.reload() 메소드를 통한 내비게이션

2(TYPE_BACK_FORWARD) : 히스토리 이동(순회) 연산을 통한 내비게이션
3(TYPE_UNDEFINED) : 위의 경우에 벗어난 네비게이션

 

5) 사용 예시
 - 해당 함수에 ios 또는 특정 브라우저 일때만 핸들링 하는 부분을 추가하여 사용하면 될 것 같다. 나와 같은 경우는 ios webview인경우 reload 처리
   물론 reload하기 때문에 화면 깜빡임 현상이 발생하였고, 페이지 캐시 효과는 없어 졌지만 당장 BFCache 로인한 에러는 해결 하였다.

 

ex1) 일반적인 사용 예

window.onpageshow = function(event){
    if ( event.persisted || (window.performance && window.performance.navigation.type == 2) ){
		alert("BFCache를 통해 페이지 접근!");
	}
};

 

ex2) 일반적인 사용 예2

<body onpageshow="if( event.persisted || (window.performance && window.performance.navigation.type == 2) ) alert("BFCache를 통해 페이지 접근!");">

 

ex3) 화살표 함수 사용

 - (https://goddaehee.tistory.com/228) 참고

window.onpageshow = (event) => {
    if ( event.persisted || (window.performance && window.performance.navigation.type == 2) ){
		alert("BFCache를 통해 페이지 접근!");
	}
};

 

ex4) jQuery 사용시

$(window).bind("pageshow", function(event) {
	if ( event.persisted || (window.performance && window.performance.navigation.type == 2) ){
		alert("BFCache를 통해 페이지 접근!");
	}
});

 

 3.2 No Cache 처리

 - developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/1.5/Using_Firefox_1.5_caching

 - 상기 내용을 확인해보면 Cache처리가 안되는 몇가지 케이스가 있는데 해당 케이스처럼 만들어 주면 캐시 처리가 안되지만, 캐싱처리를 해야하는 내용까지 캐싱처리가 안될 수 있으니 조심 해야 할 것 같다.

 

**************** 내용 참고 ****************

ㆍthe page uses an unload or beforeunload handler;
ㆍthe page sets "cache-control: no-store".
ㆍthe site is HTTPS and page sets at least one of:
  - "Cache-Control: no-cache"
  - "Pragma: no-cache"
  - with "Expires: 0" or "Expires" with a date value in the past relative to the value of the "Date" header (unless "Cache-Control: max-age=" is also specified);
ㆍthe page is not completely loaded when the user navigates away from it or has pending network requests for other reasons (e.g. XMLHttpRequest));
ㆍthe page has running IndexedDB transactions;
ㆍthe top-level page contains frames (e.g. <iframe>) that are not cacheable for any of the reasons listed here;
ㆍthe page is in a frame and the user loads a new page within that frame (in this case, when the user navigates away from the page, the content that was last loaded into the frames is what is cached).

****************************************

 

ex1) 사용 예시

@RequestMapping("/test.test")
public ModelAndView test(HttpServletRequest request, HttpServletResponse response,{
	response.setHeader("Expires", "일자"); 
	response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
	response.setHeader("Pragma", "no-cache");
}

 

나와 같은 경우는 당연히 속도 이슈도 그렇고, 리로드 하는 방법으로 해결 하였다.
이왕 이렇게 된 것 뒤로가기와 관련된 내용을 다음 포스팅으로 이어 나가도록 해야 겠다.

반응형

댓글을 달아 주세요