export http_proxy= //设置代理 export https_proxy= //设置带啦 //cd 到sdk目录下的tools/bin sudo ./sdkmanager "platform-tools" "platforms;android-34"
keytool -exportcert -alias androiddebugkeyname -keystore xxx\debug.keystore | openssl sha1 -binary | openssl base64
需要在AndroidManifest.xml的manifest节点中添加声明
<queries> <!-- TELEGRAM --> <package android:name="org.telegram.messenger" /> <!-- TELEGRAM --> <package android:name="org.telegram.messenger.web" /> <!-- Facebook --> <package android:name="com.facebook.katana" /> <!-- Twitter --> <package android:name="com.twitter.android" /> <!-- WhatsAPP --> <package android:name="com.whatsapp" /> <!-- MESSENGER --> <package android:name="com.facebook.orca" /> <!-- SNAPCHAT --> <package android:name="com.snapchat.android" /> <!-- INSTAGRAM --> <package android:name="com.instagram.android" /> </queries>
这里使用的是unity2019.4.x 以上应该也适用
但是unity打包使用的gradle是比较低版本的,不支持这个,所以打包的时候会报错,需要升级一下Gradle到5.6.4及更高版本。
一、先下载指定版本的Gradle
二、修改打包使用的Gradle,打开Editor/Preferences/External Tool

三、打开Project Settings/Player/Android/Publishing Settings,自定义Gradle

四、根据三的路径打开这两个文件,使用下面内容替换掉最上面的那行注释。在lintOptions中添加checkReleaseBuilds false。删掉相关行"useProguard **PROGUARD_DEBUG**",准备弃用了,不删会打包失败。
buildscript {
repositories {
google()
jcenter()
}
dependencies {
// Must be Android Gradle Plugin 3.6.4 or later. For a list of
// compatible Gradle versions refer to:
// https://developer.android.com/studio/releases/gradle-plugin
classpath 'com.android.tools.build:gradle:3.6.4'
}
}
allprojects {
repositories {
google()
jcenter()
flatDir {
dirs 'libs'
}
}
}public static void OpenFacebookPublicPage( String page_id , String name)
{
try {
AndroidPlugin.instance.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("fb://page/" + page_id)));
} catch (Exception e) {
//网页打开公共主页
AndroidPlugin.instance.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.facebook.com/" + name)));
}
}//判断包名是否存在
public static synchronized boolean isContainPackName( String packName) {
boolean isContainPack = false;
try {
PackageManager packageManager = AndroidPlugin.instance.getPackageManager();
PackageInfo info = packageManager.getPackageInfo(packName, PackageManager.GET_ACTIVITIES);
if (info != null) {
isContainPack = true;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return isContainPack;
}
@SuppressLint("WrongConstant")
public static void FacebookMessageShareLink(String linkurl) {
if(!isContainPackName("com.facebook.orca"))
{
Toast.makeText(AndroidPlugin.instance, "no message app", 1).show();
return;
}
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT,linkurl);//linkurl 为需要分享的内容
sendIntent.setType("text/plain");
sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sendIntent.setPackage("com.facebook.orca");//为需要分享到的包名
AndroidPlugin.instance.startActivity(sendIntent);
}public static int SavePhoto(String filePath, String fileNmae) {
if (ActivityCompat.checkSelfPermission(AndroidPlugin.instance, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
String[] mPermissionList = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
};
if (ActivityCompat.shouldShowRequestPermissionRationale(AndroidPlugin.instance, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
ActivityCompat.requestPermissions(instance, mPermissionList, SdkConst.req_code_permission_writestorage);
return 2;//忽略
}
else
{
ActivityCompat.requestPermissions(instance, mPermissionList, SdkConst.req_code_permission_writestorage);
return 0;
}
}
}
instance.runOnUiThread(new Runnable() {
public void run() {
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
File file = new File(Environment.getExternalStorageDirectory()
+ "/Pictures", fileNmae);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
Log.w("unity", e.toString());
}
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
try {
fos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.w("cat", e.toString());
}
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.w("cat", e.toString());
}
bitmap.recycle();//扫描保存的图片
instance.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment.getExternalStorageDirectory()
+ "/Pictures/" + fileNmae)));
}
});
return 1;
}服务可以和多个活动绑定,多个服务绑定的服务都是同一个实例。服务的销魂必须满足两个条件,就是服务本身没有运行并且没有和活动绑定在一起。
一、创建一个服务
public class MyService extends Service {
public class DownLoadBinder extends Binder
{
public void startDownload()
{
Log.e("MyService","开始下载");
}
public int getProgress()
{
Log.e("MyService","获取进度");
return 0;
}
}
private DownLoadBinder mBinder = new DownLoadBinder();
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
Log.e("MyService","创建");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("MyService","开始时候调用");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("MyService","销毁了");
}
}二、绑定活动和解绑活动,开启服务和停止服务
private MyService.DownLoadBinder downLoadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//iBinder为Service的onBind()返回的,用于服务和活动通信
downLoadBinder = (MyService.DownLoadBinder) iBinder;
downLoadBinder.startDownload();
downLoadBinder.getProgress();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e("chicai","断开链接");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView((R.layout.first_layout));
Button button15 = (Button)findViewById(R.id.button15);
button15.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
Intent bindIntent = new Intent(Main2Activity.this,MyService.class);
bindService(bindIntent,connection,BIND_AUTO_CREATE);//绑定活动
startService(bindIntent);//开启服务,调用onStartCommand
}
});
Button button14 = (Button)findViewById(R.id.button14);
button14.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
unbindService(connection);//解绑活动
Intent stopIntent = new Intent(Main2Activity.this,MyService.class);
stopService(stopIntent);//停止服务
}
});
}
TextView text;
public static final int UPDATE_TEXT = 1;
private Handler handle = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what)
{
case UPDATE_TEXT:
text.setText((String)msg.obj);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
text = (TextView)findViewById(R.id.textView3);
Button button13 = (Button)findViewById(R.id.button13);
button13.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try{
URL url = new URL("http://www.chicai.group");
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.connect();
int responseCode = connection.getResponseCode();
if(responseCode != HttpURLConnection.HTTP_OK) return;
InputStream in = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
String line;
StringBuilder response = new StringBuilder();
while((line = reader.readLine()) != null )
{
response.append(line);
}
//这里用Handle通知主线程修改UI
Message m = new Message();
m.what = UPDATE_TEXT;
m.obj = response.toString();
handle.sendMessage(m);
}
catch (Exception e)
{
e.printStackTrace();
}
finally {
if(reader != null)
{
try{
reader.close();
}catch (IOException e)
{
e.printStackTrace();
}
}
if(connection != null)
connection.disconnect();
}
}
}).start();
}
});
}异步消息处理机制you4个部分组成:Message、Handler、MessageQueue和Looper。
Message是线程之间传递的消息,他可以在内部携带少量的信息,用于不同线程之间交换数据。使用what字段表示什么、arg1和arg2传递整形数值、obj传递一个对象。
Handler为处理者,主要用来发送和处理消息。发送消息一般是使用Handler的sendMessage()方法,发出的消息经过一系列辗转处理后,最终会传递到Handler的handleMessage()方法。
MessageQueue是消息队列的意思,他用来存放Handler发送的消息,这部分消息会一直存放在消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
Looper是每个线程中MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。

通过URL和HttpURLConnection发送网络协议获取内容,在通过InputStream和BufferedReader读取每一行内容,网络请求不能在主线程中发送,所以需要开启一个子线程来发送网络命令。然而在子线程中也不能访问UI内容,所以又需要回到主线程中显示内容。
@Override
protected void onCreate(Bundle savedInstanceState) {
Button button13 = (Button)findViewById(R.id.button13);
button13.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try{
URL url = new URL("http://www.chicai.group");
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.connect();
int responseCode = connection.getResponseCode();
if(responseCode != HttpURLConnection.HTTP_OK) return;
InputStream in = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
String line;
StringBuilder response = new StringBuilder();
while((line = reader.readLine()) != null )
{
response.append(line);
}
ShowResponse(response.toString());
}
catch (Exception e)
{
e.printStackTrace();
}
finally {
if(reader != null)
{
try{
reader.close();
}catch (IOException e)
{
e.printStackTrace();
}
}
if(connection != null)
connection.disconnect();
}
}
}).start();
}
});
}
private void ShowResponse(final String str)
{
runOnUiThread(new Runnable() {//异步消息处理机制的接口封装
@Override
public void run() {
Toast.makeText(Main2Activity.this,str,Toast.LENGTH_LONG).show();
}
});
}