이번에는 URL 공유 시, 미리보기 정보가 보이는 기능을 만들어 보았다.
원리
URL이 인식되면, 크롤러가 해당 웹사이트의 HTML head 의 메타 데이터를 크롤링하여 미리보기 화면을 생성한다.
프로토콜
대부분 페이스북의 Open Graph 프로토콜을 사용한다.
공식 페이지: The Open Graph protocol
Jsoup을 이용하여 URL 크롤링하기
ArrayList<String> urlList, urlImage, urlTile, urlDescription;
Disposable backgroundTask;
...
// URL 크롤링하는 메소드
private void urlCrawling(String url) {
// 크롤링한 메타데이터 정보를 담아 반환할 Hashmap
HashMap<String, String> map = new HashMap<>();
backgroundTask = Observable.fromCallable(() -> {
try {
Connection con = Jsoup.connect(url);
Document doc = con.get();
Elements ogTags = doc.select("meta[property^=og:]");
if (ogTags.size() <= 0) {
return map; // 아무것도 안 들은 map 반환
}
// 필요한 OGTag
for (int i = 0; i < ogTags.size(); i++) {
Element tag = ogTags.get(i);
String text = tag.attr("property");
if("og:url".equals(text)) {
map.put("url", tag.attr("content"));
} else if ("og:title".equals(text)) {
map.put("title", tag.attr("content"));
} else if ("og:image".equals(text)) {
map.put("image", tag.attr("content"));
} else if ("og:description".equals(text)) {
map.put("description", tag.attr("content"));
}
}
return map;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<HashMap<String, String>>() {
@Override
public void accept(HashMap<String, String> map) {
if(map != null && map.get("title") != null) {
// 미리보기 화면 생성
LayoutInflater layoutInflater = getLayoutInflater();
View urlBox = layoutInflater.inflate(R.layout.item_url_crawling, urlLayout, false);
// 내용 채우기
if(map.get("image") != null) {
Glide.with(getApplicationContext()).load(map.get("image")).into((RoundedImageView)urlBox.findViewById(R.id.image));
urlImage.add(map.get("image"));
}
if(map.get("title") != null) {
((TextView)urlBox.findViewById(R.id.txt_title)).setText(map.get("title"));
urlTile.add(map.get("title"));
}
if(map.get("url") != null) {
((TextView)urlBox.findViewById(R.id.txt_url)).setText(map.get("url"));
urlList.add(map.get("url"));
}
if(map.get("description") != null) {
((TextView)urlBox.findViewById(R.id.txt_description)).setText(map.get("description"));
urlDescription.add(map.get("description"));
}
// 삭제 버튼
urlBox.findViewById(R.id.btn_deleteUrl).setOnClickListener(
v -> {
urlLayout.removeView(urlBox);
// url 리스트에서도 삭제
urlImage.remove(map.get("image"));
urlTile.remove(map.get("title"));
urlList.remove(map.get("url"));
urlDescription.remove(map.get("description"));
}
});
// 미리보기 화면 붙이기
urlLayout.addView(urlBox);
} else {
Toast.makeText(getApplicationContext(), "미리보기 정보를 가져올 수 없습니다.", Toast.LENGTH_SHORT).show();
}
backgroundTask.dispose();
}
});
}