本專案完成後的範例效果如下圖所示,左方按鈕可以進行拍照,右方紅色按鈕則可以開始進行直播
下載套件
開啟 settings.gradle.kts,在 dependencyResolutionManagement 新增 jitpack 下載庫,如下藍色設定
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven("https://jitpack.io")
}
}
開啟 build.gradle.kts(Module),新增藍色部份
android{ .............. buildFeatures{ dataBinding = true viewBinding = true } } dependencies { ............ implementation ("com.github.pedroSG94.RootEncoder:library:2.5.4") implementation ("com.github.pedroSG94.RootEncoder:extra-sources:2.5.4") }
權限
AndroidManifest.xml 新增藍色權限設定
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-feature android:name="android.hardware.camera.any" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <application
.........
Layout
RootEncoder 使用 Android 系統預設的 SurfaceView 來顯示影片,但如果直接在 Layout 置入 SurfaceView 會有問題。所以請在 Layout 中置入 LinearLayout,到了後面才由程式碼把 SurfaceView 加入 LinearLayout 中。
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:background="#000000" android:orientation="horizontal" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageButton android:alpha="0.5" android:id="@+id/btnVideo" android:layout_width="80dp" android:layout_height="80dp" android:background="@drawable/ic_video_start" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:onClick="btnVideo_click"/> <ImageButton android:alpha="0.5" android:id="@+id/btnPicture" android:layout_width="80dp" android:layout_height="80dp" android:background="@drawable/baseline_camera_24" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:onClick="btnPicture_click"/> </androidx.constraintlayout.widget.ConstraintLayout>
baseline_camera_24.xml
上述的 baseline_camera_24.xml 的代碼如下
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#7755F5" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp"> <path android:fillColor="@android:color/white" android:pathData="M9.4,10.5l4.77,-8.26C13.47,2.09 12.75,2 12,2c-2.4,0 -4.6,0.85 -6.32,2.25l3.66,6.35 0.06,-0.1zM21.54,9c-0.92,-2.92 -3.15,-5.26 -6,-6.34L11.88,9h9.66zM21.8,10h-7.49l0.29,0.5 4.76,8.25C21,16.97 22,14.61 22,12c0,-0.69 -0.07,-1.35 -0.2,-2zM8.54,12l-3.9,-6.75C3.01,7.03 2,9.39 2,12c0,0.69 0.07,1.35 0.2,2h7.49l-1.15,-2zM2.46,15c0.92,2.92 3.15,5.26 6,6.34L12.12,15L2.46,15zM13.73,15l-3.9,6.76c0.7,0.15 1.42,0.24 2.17,0.24 2.4,0 4.6,-0.85 6.32,-2.25l-3.66,-6.35 -0.93,1.6z"/> </vector>
MainActivity.kt
MainActivity.kt 先開啟權限,完整代碼如下
package net.ddns.mahaljsp.travelc import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import net.ddns.mahaljsp.travelc.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { lateinit var permission:MainPermission lateinit var ui: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //enableEdgeToEdge() ui= ActivityMainBinding.inflate(layoutInflater) setContentView(ui.root) permission= MainPermission(this) } fun init(){ //todo } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults:IntArray){ super.onRequestPermissionsResult(requestCode, permissions, grantResults) permission.result(this, requestCode) } }
Permission.kt
上述的 Permission 完整代碼如下
package net.ddns.mahaljsp.travelc import android.Manifest import android.app.AlertDialog import android.content.Context import android.content.DialogInterface import android.content.pm.PackageManager import android.os.Build import android.view.WindowInsets import android.view.WindowInsetsController import android.view.WindowManager import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat class MainPermission(context: Context) { val REQUEST_CODE = 10 val REQUIRED_PERMISSIONS = arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, ) fun allPermissionsGranted(context: Context) = REQUIRED_PERMISSIONS.all { ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED } init{ //視窗最大化 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { var controller: WindowInsetsController? = (context as MainActivity).window.insetsController controller?.hide(WindowInsets.Type.statusBars()) //controller?.hide(WindowInsets.Type.navigationBars()) } else { @Suppress("DEPRECATION") (context as MainActivity).window.setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN ) } (context as MainActivity).window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) //取得權限 if(!allPermissionsGranted(context)){ ActivityCompat.requestPermissions(context as MainActivity, REQUIRED_PERMISSIONS, REQUEST_CODE ) } else{ (context as MainActivity).init() } } fun result(context: Context,requestCode:Int){ if (requestCode== REQUEST_CODE) { if(!allPermissionsGranted(context)){ (context as MainActivity).init() val dialog= AlertDialog.Builder(context) dialog .setTitle("旅遊記") .setMessage("因您拒絕授權手機相關權限\n本程式無法提供AI派工服務\n\n若您真有需求, 請移除本程式, 並重新安裝") .setPositiveButton("離開", DialogInterface.OnClickListener{ _, _-> (context as MainActivity).finish() }) .show() } else{ (context as MainActivity).init() } } } }