我做U3D的,刚接触AndroidStudio(后面简称AS)。我想在AS上做一个下载网上apk,存放到外部存储公用文件夹下,然后打开的功能;然后打包成aar文件,给Unity用。目前一些功能都实现了,打包aar这里出现了问题。
我的下载逻辑都是写在子模块里面,但是由于子模块没法直接启动,我就从主模块跳转到了子模块来测试。现在在AS上执行能走通,能实现一个创建文件夹下载并打开的功能。现在想将这个功能打包成aar然后提供给Unity使用,问题也就出现在这里 。
我是用真机测试的,手机是安卓10的,api是29。
目前目录是这样的:
子模块,我目前的做测试,实现了一个安装apk的功能:
Unity如果想使用aar,直接调用Call方法就行。
但是由于安卓10以后,访问外部储存需要用户授权,就是手机会弹出一个框,让你点确定才能授权。逻辑用到了onRequestPermissionsResult 这个方法,它是继承Activity类实现的方法。就是说,必须在AS这边有一个界面才行,(不确定,是不是必须要一个界面)
我现在有一个想法,就是unity那边跳转界面到这AS主模块,然后跳到子模块,再开始执行逻辑。
还有个想法就是全部逻辑都写到AS这边来,界面也在这边做,再弄一个unity的apk执行下载完成的事件,这边做完了启动unity的apk。
但是我感觉两种方案都不好,要是拿授权不需要界面就好了,就能直接调用AS这边的方法。
没做过安卓,我现在比较迷茫,希望有人能帮我解惑,我改怎么做才好呢?
我的AS工程 https://gitee.com/fancaihua/android-response.git
// 安装APK包
private void installApk() {
File file = new File("/storage/emulated/0/CreateParty/Install/DJ_Install.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = FileProvider.getUriForFile(this, "com.fch.loadlib.fileprovider", file);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);
}
public void requestStoragePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE_PERMISSION);
} else {
// 如果系统版本低于 6.0,则默认具有存储权限
installApk();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_STORAGE_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 如果用户授予了存储权限,则开始下载 APK 文件
installApk();
} else {
// 如果用户拒绝了存储权限,则提示用户
Toast.makeText(this, "存储权限被拒绝", Toast.LENGTH_SHORT).show();
}
}
}
该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
子模块是无法单独启动的,因为它们是被包含在主模块中的一部分。如果您想要在Unity中使用您的下载网上apk的功能,最好的方法是将它们放在主模块中,并将主模块打包成aar文件。
关于访问外部存储需要用户授权的问题,您可以在主模块中添加一个Activity来处理授权请求,这个Activity不需要提供任何UI界面,只需要在onCreate方法中执行授权逻辑即可。在您的子模块中调用这个Activity即可。
下面是一个示例代码,用于在主模块中添加一个处理授权请求的Activity:
public class PermissionActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestStoragePermission();
}
private void requestStoragePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE_PERMISSION);
} else {
// 如果系统版本低于 6.0,则默认具有存储权限
finish();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_STORAGE_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
setResult(RESULT_OK);
} else {
setResult(RESULT_CANCELED);
}
finish();
}
}
}
在您的子模块中,您可以使用下面的代码来调用这个Activity,处理授权请求:
Intent intent = new Intent(context, PermissionActivity.class);
context.startActivityForResult(intent, REQUEST_CODE_STORAGE_PERMISSION);
在主模块中,您需要在AndroidManifest.xml文件中声明这个Activity:
<activity android:name=".PermissionActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"/>
这样,当您的子模块需要访问外部存储时,它会自动跳转到这个Activity,请求授权。一旦授权成功,子模块就可以继续执行下载逻辑了。
希望这些信息对您有所帮助!
如果以上回答对您有所帮助,点击一下采纳该答案~谢谢
以下内容引用CHATGPT、有用望采纳:
首先,子模块是不能单独启动的,因为它没有自己的入口,必须要由主模块启动。
其次,如果你想将下载逻辑打包成aar文件提供给Unity使用,建议将所有逻辑都写在AS中,包括请求权限和下载文件等。这样,Unity只需要调用aar文件中的方法就可以了,不需要关心权限和逻辑的实现。
最后,关于权限请求必须要有界面的问题,建议在AS中创建一个透明的Activity作为权限请求的界面。当Unity调用aar文件中的方法时,AS会启动这个Activity,请求权限。如果用户授权,AS会在回调中执行下载逻辑。如果用户拒绝授权,AS可以弹出一个提示框告诉用户需要权限才能执行下载逻辑。
下面是请求权限的示例代码:
public class PermissionActivity extends AppCompatActivity {
private static final int REQUEST_CODE_STORAGE_PERMISSION = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestStoragePermission();
}
private void requestStoragePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE_PERMISSION);
} else {
// 如果系统版本低于 6.0,则默认具有存储权限
onPermissionGranted();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_STORAGE_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 如果用户授予了存储权限,则开始下载 APK 文件
onPermissionGranted();
} else {
// 如果用户拒绝了存储权限,则提示用户
Toast.makeText(this, "存储权限被拒绝", Toast.LENGTH_SHORT).show();
}
}
}
private void onPermissionGranted() {
// 在这里执行下载逻辑
}
}
在AndroidManifest.xml中添加如下代码:
<activity android:name=".PermissionActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
这样,当Unity调用aar文件中的方法时,AS会启动PermissionActivity请求权限,然后回调执行下载逻辑。
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
首先,对于AS子模块能否单独启动的问题,答案是肯定的。你可以在子模块里实现一个Activity,然后在AndroidManifest.xml文件里配置这个Activity,并设置启动方式为singleTask或singleInstance,这样就可以在AS中直接启动这个子模块的Activity了。关于启动模式的详细说明,请参考官方文档。
其次,关于打包成aar文件给Unity使用的问题,也可以通过在子模块中实现一个接口或者使用全局广播的方式来实现。你可以在子模块中添加一个类似于"DownloadManager"的类,用来管理下载任务和完成下载之后的操作,然后在子模块的AndroidManifest.xml文件里声明一个接收系统广播的接收器类,在下载完成后发送广播,主模块中注册广播接收器,接收到广播后调用子模块中的接口,从而实现在Unity中使用。
这种方式需要在子模块中实现两部分:下载和广播。这样主模块调用子模块下载功能后,下载完成后发好广播,然后在主模块接收广播并调用子模块中的接口实现下载成功后的逻辑。
关于授权的问题,由于Android 6.0(API level 23)及以上版本需要动态请求权限,所以需要在AS中申请存储权限。如果你希望用户在启动应用程序后授权,可以在AS这边创建一个引导界面,用户启动应用时会弹出申请权限的对话框,用户同意授权后才能使用下载功能。如果你希望用户在使用下载功能时授权,可以在下载函数中添加请求权限的代码,如果用户已经授权,将执行安装apk的操作。具体代码可以参考以下:
在子模块中:
// 检查权限并下载apk
public void downloadApk(Activity activity, String url) {
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestStoragePermission(activity);
return;
}
startDownload(activity, url);
}
public void requestStoragePermission(Activity activity) {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSIONS_REQUEST_CODE_STORAGE);
}
private void startDownload(Activity activity, String url) {
// 下载逻辑代码
// ......
// 下载完成后,发送广播通知主模块下载完成
Intent intent = new Intent("com.example.download.APK_DOWNLOAD_COMPLETE");
intent.putExtra("apk_path", mApkFilePath);
activity.sendBroadcast(intent);
}
在AS主模块中:
private BroadcastReceiver mDownloadReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.example.download.APK_DOWNLOAD_COMPLETE")) {
String apkPath = intent.getStringExtra("apk_path");
// 下载完成后,调用子模块中的接口进行下一步操作
mSubModule.installApk(apkPath);
}
}
};
// 注册广播接收器
private void registerDownloadReceiver() {
IntentFilter filter = new IntentFilter("com.example.download.APK_DOWNLOAD_COMPLETE");
registerReceiver(mDownloadReceiver, filter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSubModule = new SubModule();
// 注册广播接收器
registerDownloadReceiver();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSIONS_REQUEST_CODE_STORAGE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户允许了权限,开始下载
mSubModule.downloadApk(this, DOWNLOAD_URL);
} else {
// 用户拒绝了权限,提示用户
Toast.makeText(this, "权限被拒绝,无法下载apk", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
这样,Unity可以直接调用主模块中的downloadApk函数进行下载,并在下载完成后接收广播实现对应的操作。如果你想让用户在启动应用程序之前就授权,可以参考以下代码:
在AS启动界面的onCreate函数中,添加下面的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
// 动态申请存储权限
requestStoragePermission();
}
private void requestStoragePermission() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSIONS_REQUEST_CODE_STORAGE);
} else {
// 已经授权,进入主界面
startActivity(new Intent(this, MainActivity.class));
finish();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSIONS_REQUEST_CODE_STORAGE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户允许了权限,进入主界面
startActivity(new Intent(this, MainActivity.class));
finish();
} else {
// 用户拒绝了权限,关闭应用程序
Toast.makeText(this, "应用程序需要存储权限才能运行,请允许授权",
Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
break;
}
}
这样,在用户启动应用程序时,会弹出授权对话框,用户同意授权后才能进入主界面。
如果我的回答解决了您的问题,请采纳!