Многие начинающие разработчики задумываются о том, как сделать собственный браузер прямо в Android Studio. На первый взгляд задача кажется сложной, но на деле всё сводится к использованию готового компонента WebView, который уже встроен в операционную систему. В этом руководстве мы пройдём путь от пустого проекта до работающего мини-браузера с адресной строкой, кнопками навигации и поддержкой загрузки страниц. Писать будем на Kotlin, а все действия разберём по шагам, чтобы справился даже новичок.
Что понадобится для браузера
Основой будущего браузера станет WebView — компонент, который использует движок WebKit для отображения веб-страниц. Он умеет загружать сайты по URL, выполнять JavaScript и корректно обрабатывать переходы по ссылкам. Помимо него нам потребуются поле ввода адреса, кнопки «Назад», «Вперёд» и «Обновить», а также индикатор загрузки. Все эти элементы мы разместим в одном экране и свяжем с WebView.
Для доступа в интернет нужно добавить разрешение в манифест. Без него WebView не сможет загрузить ни одну страницу. Также стоит разрешить использование незащищённого трафика, если вы планируете тестировать на локальных HTTP-ресурсах.
Добавление разрешений в манифест
Откройте файл AndroidManifest.xml и внутри тега <manifest> добавьте разрешение на интернет. Для поддержки HTTP (не только HTTPS) добавьте атрибут usesCleartextTraffic в тег <application>.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.browser">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Browser"
android:usesCleartextTraffic="true">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Обратите внимание, что usesCleartextTraffic стоит включать только для разработки. В реальном проекте лучше использовать HTTPS, чтобы не подвергать пользователей риску.
Создание интерфейса браузера
Разметка браузера состоит из верхней панели с полем ввода и кнопками, и самого WebView, занимающего всё оставшееся место. Для удобства расположим элементы вертикально: сначала строка управления, затем область отображения страницы.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<Button
android:id="@+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="<" />
<Button
android:id="@+id/btnForward"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=">" />
<EditText
android:id="@+id/etUrl"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Введите адрес"
android:inputType="textUri" />
<Button
android:id="@+id/btnGo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Перейти" />
<Button
android:id="@+id/btnRefresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="⟳" />
</LinearLayout>
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Кнопки «Назад» и «Вперёд» позволят перемещаться по истории посещённых страниц, «Перейти» загрузит введённый URL, а «Обновить» перезагрузит текущую страницу.
Инициализация WebView и обработка навигации
В MainActivity.kt получим ссылки на все элементы, настроим WebView и свяжем кнопки с действиями. Прежде всего включим поддержку JavaScript — без него многие современные сайты будут отображаться некорректно. Затем установим WebViewClient, чтобы переходы по ссылкам происходили внутри WebView, а не открывались во внешнем браузере.
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
private lateinit var etUrl: EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.webView)
etUrl = findViewById(R.id.etUrl)
val btnBack = findViewById<Button>(R.id.btnBack)
val btnForward = findViewById<Button>(R.id.btnForward)
val btnGo = findViewById<Button>(R.id.btnGo)
val btnRefresh = findViewById<Button>(R.id.btnRefresh)
webView.settings.javaScriptEnabled = true
webView.webViewClient = WebViewClient()
btnGo.setOnClickListener {
var url = etUrl.text.toString().trim()
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "https://$url"
}
webView.loadUrl(url)
}
btnBack.setOnClickListener {
if (webView.canGoBack()) webView.goBack()
}
btnForward.setOnClickListener {
if (webView.canGoForward()) webView.goForward()
}
btnRefresh.setOnClickListener {
webView.reload()
}
}
}
Теперь пользователь может ввести адрес вручную и перейти по нему, а кнопки навигации работают по назначению.
Обработка переходов по ссылкам
Чтобы все клики по ссылкам внутри загруженной страницы обрабатывались внутри WebView, нужно переопределить метод shouldOverrideUrlLoading в нашем WebViewClient. По умолчанию WebView уже делает это, но явная реализация даёт больше контроля и гарантирует правильное поведение на всех версиях Android.
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
): Boolean {
val url = request?.url?.toString() ?: return false
view?.loadUrl(url)
return true
}
}
Также полезно обновлять адресную строку после перехода, чтобы она всегда показывала актуальный URL. Для этого добавим слушатель doUpdateVisitedHistory, который срабатывает при изменении истории навигации.
webView.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
// можно отобразить прогресс загрузки
}
}
webView.webViewClient = object : WebViewClient() {
// ...
override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) {
etUrl.setText(url)
}
}
Индикатор загрузки
Чтобы пользователь видел, что страница загружается, добавим горизонтальный ProgressBar над WebView. В разметке поместим его между панелью управления и WebView:
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:visibility="gone" />
В коде подключим WebChromeClient и будем обновлять прогресс в методе onProgressChanged:
webView.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
val progressBar = findViewById<ProgressBar>(R.id.progressBar)
progressBar.progress = newProgress
if (newProgress == 100) {
progressBar.visibility = View.GONE
} else {
progressBar.visibility = View.VISIBLE
}
}
}
Сохранение состояния при повороте экрана
При повороте устройства Activity пересоздаётся, и WebView теряет текущую страницу. Чтобы этого избежать, нужно сохранить состояние в onSaveInstanceState и восстановить в onCreate.
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
webView.saveState(outState)
}
override fun onCreate(savedInstanceState: Bundle?) {
// ...
if (savedInstanceState != null) {
webView.restoreState(savedInstanceState)
}
}
Теперь после поворота страница останется на месте, и пользователю не придётся заново вводить адрес.
Полезные дополнения
- Обработка ошибок загрузки. Переопределите
onReceivedErrorвWebViewClient, чтобы показывать сообщение об ошибке вместо пустого экрана. - Разрешение на файлы. Для поддержки загрузки файлов используйте
DownloadListenerиsetDownloadListener. - Инкогнито-режим. WebView поддерживает
settings.setSupportMultipleWindows(false)и другие параметры, которые могут пригодиться при построении приватного браузера.
Что мы получили в итоге
Мы собрали полноценный мини-браузер на базе WebView. Он умеет загружать страницы по URL, отображать ссылки внутри себя, поддерживает кнопки навигации и индикатор загрузки. Код получился компактным, а функциональность можно легко расширять. Попробуйте добавить закладки или историю посещений — это станет отличным продолжением данного урока. Теперь вы знаете, как сделать браузер в Android Studio на Kotlin, и можете гордиться своим первым полноценным приложением.