Tips:以下是为了给Unity用的
构建aar
过程
准备工作
首先创建一个AndroidStudio工程,再新建一个模块,模块的名字无所谓,遵循.com.xxx.xxx就可以
以Unity2021.3.6自带的gradle插件版本4.0.1 gradle版本6.1.1举例子
AndroidStudio版本是2021.3.1
然后在AndroidStudio中File-->Project Structure-->Project中
修改Gradle Plugin Version 和Gradle Version
修改成和Unity中的一样 你也可以用别的Gradle版本(下面有插件版本和版本对应关系的官方链接)
如果你不想用Unity自己的Gradle版本 请到后面找修改方法
然后你就可以开始写代码了
开始写代码
首先,如果你不需要UnityPlayer库(2021.3.6f1c1\Editor\Data\PlaybackEngines\AndroidPlayer
\Variations\il2cpp\Release\Classes\classes.jar),或者说你不需要通知Unity那就不用导入
如果需要那就把这个jar包复制粘贴到刚新建的模块的libs目录下,
然后点右键Add as library,这是为了添加依赖
让你的代码能够识别到这个库,然后就可以开始写代码了
这里举一个例子:打开图库选择图片并返回图片路径和剪切板
Tips:UnityPlayer.currentActivity是Unity当前的活动窗口,跳转活动窗口必须这样跳,还有Activity之间传参数
需要注意的是自己写的Activity千万不要继承UnityPlayerActivity
因为在调用finish的时候会直接调用到UnityPlayerActivity的OnDestroy,结果就是应用退出
单纯的继承Activity就可以了
Gradle其实是Groovy语言,不同版本的Gradle语法是不一样的,看着报错改就可以
重要的:自己写的Activity需要在Unity的AndroidManifest里面声明这个Activity
写法:在Application标签下添加一个Activity标签
<activity android:name="com.xxx.xxx.xxxActivity"></activity>
Intent intent = new Intent(context, xxxActivity.class);
context.startActivity(intent);
这个是MainActivity
// 这里改自己的包名
package com.xxx.xxx;
import com.unity3d.player.UnityPlayer;
public class MainActivity {
public static void OpenPic(){
WebViewActivity.launch(UnityPlayer.currentActivity);
}
public static void CopyTextToClipboard(String str) throws Exception {
ClipboardHelper.copyTextToClipboard(UnityPlayer.currentActivity, str);
}
}
这个是图库的Activity
// 这里改自己的包名
package com.xxx.xxx;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import com.unity3d.player.UnityPlayer;
import java.io.IOException;
public class WebViewActivity extends Activity {
public static final String IMAGE_UNSPECIFIED = "image/*";
private static final int PICK_IMAGE_REQUEST_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 启动图库选择器
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED);
startActivityForResult(intent, PICK_IMAGE_REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
String path = getImagePath(uri);
// 如果选择了图片 就返回图片路径
// 第一个参数是接收消息的GameObject的name
// 第二个参数是GameObject身上挂载的脚本里的方法
// 第三个参数是方法的参数(只能是字符串)
UnityPlayer.UnitySendMessage("SDKManager", "GetPhoto", path);
} else if (resultCode == RESULT_CANCELED) {
// 没有选择直接退出就返回空字符串
UnityPlayer.UnitySendMessage("SDKManager", "GetPhoto", "");
}
}
finish();
}
private String getImagePath(Uri uri)
{
if(null == uri) return null;
String path = null;
final String scheme = uri.getScheme();
if (null == scheme) {
path = uri.getPath();
} else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
path = uri.getPath();
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(uri, proj, null, null,
null);
int nPhotoColumn = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (null != cursor) {
cursor.moveToFirst();
path = cursor.getString(nPhotoColumn);
}
cursor.close();
}
return path;
}
public static void launch(Context context){
Intent intent = new Intent(context, WebViewActivity.class);
context.startActivity(intent);
}
}
这个是调用剪切板
// 这里改自己的包名
package com.xxx.xxx;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.content.Context;
import android.util.Log;
public class ClipboardHelper {
public static ClipboardManager clipboard = null;
public static void copyTextToClipboard(Context activity, String str) throws Exception {
clipboard = (ClipboardManager) activity.getSystemService(Activity.CLIPBOARD_SERVICE);
ClipData clipData = ClipData.newPlainText("data", str);
clipboard.setPrimaryClip(clipData);
}
public static String getTextFromClipboard() {
if (clipboard != null && clipboard.hasPrimaryClip() && clipboard.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
ClipData cdText = clipboard.getPrimaryClip();
ClipData.Item item = cdText.getItemAt(0);
return item.getText().toString();
} else {
return "";
}
}
}
这里贴上模块的AndroidManifest.xml和build.gradle
<?xml version="1.0" encoding="utf-8"?>
<!-- 改成自己的包名 -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xxx.xxx">
<!-- 读写权限 -->
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application>
<!-- 改成自己的包名 -->
<activity android:name="com.xxx.xxx.WebViewActivity"/>
</application>
</manifest>
plugins {
// 这里一定是com.android.library
id 'com.android.library'
}
android {
compileSdkVersion 32
defaultConfig {
minSdkVersion 22
targetSdkVersion 32
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation files('libs\\unitylib.jar')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
这个是项目的build.gradle
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
// 这里是修改gradle插件版本的地方
classpath 'com.android.tools.build:gradle:4.0.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
打aar包,这里很重要
可以打包了,先点击一下模块文件夹,再点工具栏的Build/Make Moudle '项目名称.模块名称'
打包出来之后到当前模块的目录下找到build/outputs/aar这里放着的就是打出来的aar包
接着我们需要对aar包进行处理,用压缩工具打开它,它里面有个libs文件夹,
把libs文件夹里的Unity里复制粘贴过来的jar包删掉(因为Unity打包的时候会自己带着这个jar包)
然后返回上级目录打开jar包,把BuildConfig.java文件删除掉(因为Unity打包的时候会自己生成)
然后应用修改,关闭,然后就可以把它放到Unity里面了,路径是Plugins/Android/
Tips:再说一遍AS的Gradle插件版本和Gradle版本和Unity的Gradle插件版本和Gradle版本一定要对应上
这里是Unity中修改Gradle插件版本和Gradle版本
Unity中
Edit-->Preferences-->External Tools可以修改Gradle版本
Edit-->Project Settings-->Player-->Publishing Settings-->Build 勾选Custom Base Gradle Template
勾选后会在Assets/Plugin/Android路径下生成baseProjectTemplate.gradle文件
这个相当于是AS项目的项目build.gradle可以修改Gradle插件版本
Custom Main Manifest会生成AndroidManifest文件,
在这里面可以声明权限,声明Activity
最后贴一个Unity打包生成的Gradle项目的路径UnityProject\Library\Bee\Android\Prj\IL2CPP\Gradle
如果说打包的时候有Gradle构建的报错,到这里看Gradle为什么报错
然后在Unity中调用这个aar包
private const string NoPath = "NoPath";
private AndroidJavaObject _mainActivity;
private string _path = NoPath;
/// <summary>
/// 获取图片地址调用这个
/// </summary>
/// <param name="onSelect"></param>
public void OpenPic(Action<PicPathResult, string> onSelect)
{
try
{
if (_mainActivity == null)
{
_mainActivity = new AndroidJavaObject("com.xxx.xxx.MainActivity");
}
_mainActivity.CallStatic("OpenPic");
StartCoroutine(WaitForPath(onSelect));
}
catch (System.Exception ex)
{
onSelect.Invoke(PicPathResult.Failed, string.Empty);
}
}
public void CopyText(string format, params object[] args)
{
string result = string.Format(format, args);
_mainActivity.CallStatic("CopyTextToClipboard", result);
}
private IEnumerator WaitForPath(Action<PicPathResult, string> onSelect)
{
while (string.Equals(_path, NoPath))
{
yield return null;
}
if (string.IsNullOrEmpty(_path))
{
onSelect?.Invoke(PicPathResult.Failed, string.Empty);
}
else
{
onSelect?.Invoke(PicPathResult.Success, _path);
}
_path = NoPath;
}
/// <summary>
/// 不许删
/// </summary>
/// <param name="path"></param>
public void GetPhoto(string path)
{
_path = path;
}
public enum PicPathResult{
Success, Failed
}
结束语:写完下班啦