Things take time

[Android] TextView에 Linkify로 링크 걸기 및 액티비티 이동 본문

Android(기능)

[Android] TextView에 Linkify로 링크 걸기 및 액티비티 이동

겸손할 겸 2020. 1. 15. 16:05

[Linkify]

 

layout.xml 안에 TextView의 속성중 autoLink라는 속성이 있다.

해당 속성은 텍스트 뷰안에 url web 속성이나 연락처(phone), 이메일(email) 형식이 있을 경우, 자동으로 필터링 되어 해당 문구에 링크를 걸고 링크 클릭시, 웹 이동/전화 걸기/이메일 작성 등의 작업을 수행할 수 있다.

 

기본만 필요하다면, 사용하기 유용한 속성중 하나인데 만약, 이 기능을 커스터마이징 하고싶을때를 가정한다.

 

예를들어, 특정한 문자열이 나타나면 액티비티를 이동하고 싶을 때라는 것이다. 아니면 기본 속성을 사용하지 않고 카카오톡에서 대화 말풍선 내 링크가 있을 때, 그 링크를 클릭하면 이동하는 기본 핸드폰에 깔린 웹 앱(삼성 브라우저, 구글 크롬 등)을 실행시키는 방법의 ACTION_VIEW가 아니라, 카카오톡에서 자체 적으로 사용하는 웹뷰가 뜨는 것처럼 말이다.

나는 이 기능을 만들 것이다.

 

[선수 조건]

기본적으로 TextView속성에 autoLink가 걸려있다면, 해당 속성을 제거한다.

 

[코드]

findViewById(R.id.textView).setText("안녕하세요 링크는 https://g-y-e-o-m.tistory.com/");
String urlStr = "https://tistory.com";
Linkify.TransformFilter mTransform = new Linkify.TransformFilter() {
  @Override
 	 public String transformUrl(Matcher match, String url) {
  		return "";
  }
};
Pattern pattern = Pattern.compile("(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$");
Linkify.addLinks(R.id.textView, pattern, urlStr , null, mTransform);

1) 텍스트 뷰의 대화상자에는 안녕하세요 링크는 https://g-y-e-o-m.tistory.com/ 이란 문자열이 들어가있다.

2) urlStr은 해당 링크를 클릭했을 때 이동되는 링크이다.

3) mTransform은 addLinks라는 함수를 통해, 텍스트 뷰 안에 있는 문자열이 패턴에 검색되어 검출되었을 때, urlStr로 이동되기 전 호출되는 함수이다. ""를 리턴하는 것은 urlStr로 이동할 때, 텍스트 뷰 안에 있던 찾은 문자열을 urlStr뒤에 붙이기 때문에 ""로 리턴한다.

만약 mTransform대신 null을 넣으면, htts://tistory.comhttps://g-y-e-o-m.tistory.com/ 이렇게 붙여진단 뜻! 그러므로 패턴으로 찾은 애는 ""로 변경해주면 된다.

 

**  mTransform대신 null을 넣었을 때

 

4) 패턴은 정규식으로 들어가며, URL을 검출한다. 텍스트 뷰 안 문자열 중간에 url이 들어있을 수 있으므로 위와 같다.

 

위와 같이 사용할 경우 아래와 같은 화면이 나타나고, 클릭 시 기본 웹 브라우저가 열리며, 티스토리 메인 페이지로 이동한다.

 

 

[커스텀 코드]

Pattern pattern = Pattern.compile("(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$");
Linkify.addLinks(holder.msgCont, pattern, "tlkwebview://?url=" + urlStr , null, mTransform);

1) 이동되는 urlStr을 그대로 사용하지 않고, 커스텀 스키마를 통해 url이란 파라미터에 전달하도록 했다.

2) 매니페스트에 등록된 tlkwebview란 액티비티는 다음과 같이 작성되었다.

        <activity android:name=".common.TlkWebView">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data
                    android:scheme="tlkwebview" />
            </intent-filter>
        </activity>

common이란 폴더 밑에 TlkWebView란 클래스 파일로 작성되었으며, 인텐트 필터로 액션, 카테고리를 지정해주었다.

그리고 data안에 scheme이란 스키마 값을 주었다. 호스트란 값도 줄 수 있지만, 용도에 따라 주지 않아도 된다.

 

그리고 한가지 주의할 점

Linkify에 이동되는 스키마 패턴 및 url에는 대문자가 소문자로 자동 변경되므로, 소문자로 사용하도록 한다.

 

그러나 대문자는 대문자, 소문자는 소문자로 가야한다면 아래와 같이 변경한다.

Linkify.TransformFilter mTransform = new Linkify.TransformFilter() {
  @Override
    public String transformUrl(Matcher match, String url) {
    return url;
  }
};

물론 스키마라면, return "tlkwebview://?url=" + url; 이다.

 

이제 스키마 작성은 마쳤으니, 해당 액티비티에서 getIntent()를 검사하자.

        if(getIntent() != null){
            if(getIntent().getData() != null){
                // 스키마
                webViewUrl = getIntent().getData().getQueryParameter("url");
            }else {
                // 인텐트
                webViewUrl = getIntent().getStringExtra("webViewUrl");
            }
        }

1) getIntent()로 넘어올수 있는 것은 startActivity와 스키마를 통해 넘어올 수 있다. 다만, 스키마로 넘어온 경우는 getData()가 null이 아니므로 위와 같이 사용한다. 나는 이 액티비티를 스키마전용이 아니라 다른 곳에서도 넘어와 사용할 수 있도록 하기위해 위처럼 작성했다.

 

2) 그리고 위 화면에서 다시 링크를 클릭하면 아래와 같다.

위의 파란색 헤더에 새로고침, 닫기 버튼은 네이티브로 작성해서, 웹뷰로 열렸단 것을 보여준 것이다.

이제 여기에 웹뷰의 스크롤 이벤트를 커스터마이징해서 애니메이션 헤더 숨김, 보이기 하면 카톡과 같은 웹뷰가 된다.

 

 

** 추가사항

스키마로 넘어온 Uri값에 '&'와 같은 특수문자 올 때

 

만약 getIntent().getData()안에 넘어온 쿼리값에 특수문자가 포함이 되어있다면, getQueryParameter('key값')을 통해 얻어오면 특수문자 전까지만으로 짤리게 된다.

 

그래서 나는 getUrl(getIntent().getData().toString())으로 그냥 문자열을 넘겨주고, 파라미터 값은 알고있으므로, 그 값을 검출해서 뽑아내도록 했다.

    private String getUrl(String schemeUrl){
        String returnString = "";
        if(schemeUrl.contains("url=")){
            int findIdx = schemeUrl.indexOf("url=");
            returnString = schemeUrl.substring(findIdx + 4, schemeUrl.length());
            Log.e("getUrl", returnString);
        }
        return returnString;
    }