首页 文章 精选 留言 我的

精选列表

搜索[包体优化],共10000篇文章
优秀的个人博客,低调大师

Xamarin.Android 调用原生的Jar包

我们有时候会从Android原生开发(Java)转移到Xamarin.Android开发时,需要将过去写好的Android Class Library直接嵌入到Xamarin.Android底下使用,这样就不再从新写一遍代码了。 提示:滚动条看着短,实际截图多,看之前不要慌~ 在Eclipse中制作Android Class Library的jar文件 项目建立完会有一个 New Android Application填写框 接着在项目的src文件夹下点选右键,选单当中New->Package,来建立该ClassLibrary的程序所在的Package。 新增完成后在此项目当中呈现的效果: 接着在这个Package底下继续增加类别程序代码档。在Package上右键选单中,点选New->Class。 接着将这个类别命名为MyMathClass,点选Finish。 完成后继续增加点程序代码,在这个类别当中,增加了两个静态方法,供之后引用的项目可以直接使用。 接着直接在项目上右键选单,点选Build Project(使用截图老是把右键出来的子菜单给屏蔽掉,所里这里没有做截图)。 然后展开项目当中的bin文件夹,应该就可以看到我们终于制作出androidclasslibraryprojecttest.jar可以让应用项目使用。 接着开始弄C#环境: 在新增C#项目的模板当中,选到Xamarin.Android的项目模板,这边采用默认名称App1,接着点选确定。 接着在解决方案中添加一个新建项目 在项目模板当中,选到BindingsLibrary(Android)的模板后,将此项目取名为MyBindingsClassLibrary后,点选确定。 现在解决方案中呈现的效果 在新增好的BindingsLibrary项目当中,找到jar文件夹在上面右键选单,添加-->现有项 调整该Jar文件属性当中的生成操作为EmbeddedJar。 在MyBindingsClassLibrary的专案档上右键选单,点击生成。 回到App1项目中的右键引用,将MyBindingsClassLibrary添加到引用项。 加入引用完成后,在解决方案呈现的效果。 接着我们打开App1项目当中的MainActivity.cs档,来添加一些测试的程序代码。 最后的测试结果:

优秀的个人博客,低调大师

ASCSDK-------通用包接入文档(UNITY篇)

1. Untiy接入文档------Android端 Android端的作用是对接ASCSDK打包工具与unity原生端的中间件。 ASCUnityContext是主要的连接类,这个类继承UnityPlayerActivity ,也是游戏的启动Activity。 package com.asc.sdk; import java.util.List; import org.json.JSONException; import org.json.JSONObject; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.asc.sdk.platform.ASCExitListener; import com.asc.sdk.platform.ASCInitListener; import com.asc.sdk.platform.ASCPlatform; import com.asc.sdk.plugin.ASCUser; import com.asc.sdk.verify.UToken; import com.unity3d.player.UnityPlayer; import com.unity3d.player.UnityPlayerActivity; /*** * 记得将游戏工程中的AndroidManifest.xml中application节点,增加一个android:name="ASCApplication" * 如果游戏有自己的Application。那么通过实现IApplicationListener接口来实现,而不要使用继承Application。 * 然后将自己的Application类,配置到AndroidManifest.xml中的meta-data节点中,name为"ASC_Game_Application" * @author xiaohei * */ public class ASCUnityContext extends UnityPlayerActivity{ public final static String CALLBACK_GAMEOBJECT_NAME = "(ascsdk_callback)"; //unity中接收回调通知的GameObject的名称 public final static String CALLBACK_INIT = "OnInitSuc"; //SDK初始化成功的回调方法名称和Unity中一致 public final static String CALLBACK_LOGIN = "OnLoginSuc"; //SDK登录成功的回调方法名称和Unity中一致 public final static String CALLBACK_SWITCH_LOGIN = "OnSwitchLogin"; //SDK切换帐号的回调方法名称和Unity中一致 public final static String CALLBACK_LOGOUT = "OnLogout"; //SDK登出的回调方法名称和Unity中一致 public final static String CALLBACK_PAY = "OnPaySuc"; //SDK支付成功回调方法名称和Unity中一致 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initSDK(); } private void initSDK(){ ASCPlatform.getInstance().init(this, new ASCInitListener() { @Override public void onSwitchAccount(UToken data) { //游戏中通过SDK切换到新账号的回调,游戏收到该回调,需要引导用户重新登录,重新加载该新用户对应的角色数据 if(data == null){ tip("切换帐号失败,请重试"); return; } sendLoginResult(data, true); } @Override public void onPayResult(int code, String msg) { Log.d("ASCSDK", "pay result. code:"+code+";msg:"+msg); /*switch(code){ case ASCCode.CODE_PAY_SUCCESS: //tip("支付成功"); break; case ASCCode.CODE_PAY_FAIL: //tip("支付失败"); break; case ASCCode.CODE_PAY_CANCEL: //tip("支付取消"); break; case ASCCode.CODE_PAY_UNKNOWN: //tip("支付失败,未知错误"); break; }*/ } @Override public void onLogout() { //用户登出回调(需要收到该回调需要返回游戏登录界面,并调用login接口,打开SDK登录界面) sendCallback(ASCUnityContext.CALLBACK_LOGOUT, null); } @Override public void onLoginResult(int code, UToken data) { switch(code){ case ASCCode.CODE_LOGIN_SUCCESS: sendLoginResult(data, false); tip("登录成功"); break; case ASCCode.CODE_LOGIN_FAIL: tip("登录失败"); break; } } @Override public void onInitResult(int code, String msg) { Log.d("ASCSDK", "init result.code:"+code+";msg:"+msg); switch(code){ case ASCCode.CODE_INIT_SUCCESS: sendCallback(CALLBACK_INIT, null); tip("初始化成功"); break; case ASCCode.CODE_INIT_FAIL: tip("初始化失败"); break; } } @Override public void onProductQueryResult(List<ProductQueryResult> result) { // TODO Auto-generated method stub } @Override public void onVideoResult(int code, String msg) { // TODO Auto-generated method stub Log.d("ASCSDK", "onVideoResult result:"+msg); Toast.makeText(ASCUnityContext.this, "视频回调成功", Toast.LENGTH_LONG).show(); } @Override public void onSinglePayResult(int code, ASCOrder order) { Log.d("ASCSDK", "onSinglePayResult result:"+order.getProductID()); JSONObject json = new JSONObject(); String pId = ""; pId = order.getProductID(); try{ if(code == ASCCode.CODE_PAY_SUCCESS){ json.put("payResult", 0); }else{ json.put("payResult", 1); } json.put("productId", pId); }catch(Exception e){ e.printStackTrace(); } sendCallback(ASCUnityContext.CALLBACK_PAY,json.toString()); } @Override public void onDestroy() { // TODO Auto-generated method stub } }); } public void sendLoginResult(UToken authResult, boolean isSwitchAccount) { JSONObject json = new JSONObject(); try{ json.put("isSuc", authResult.isSuc()); json.put("isSwitchAccount", isSwitchAccount); if(authResult.isSuc()){ json.put("userID", authResult.getUserID()); json.put("sdkUserID", authResult.getSdkUserID()); json.put("username", authResult.getUsername()); json.put("sdkUsername", authResult.getSdkUsername()); json.put("token", authResult.getToken()); } }catch(Exception e){ e.printStackTrace(); } this.sendCallback(ASCUnityContext.CALLBACK_LOGIN, json.toString()); } public void nativeLog(String msg){ Log.d("ASC_LOG_UNITY", msg); } //登录接口 public void login(){ ASCPlatform.getInstance().login(this); } //显示用户中心接口 public void showAccountCenter(){ ASCPlatform.getInstance().showAccountCenter(); } //登出 public void logout(){ ASCPlatform.getInstance().logout(); } //提交扩展数据 public void submitExtraData(String data){ final UserExtraData extraData = parseGameData(data); ASCPlatform.getInstance().submitExtraData(extraData); } //SDK退出接口 public void exit(){ ASCPlatform.getInstance().exitSDK(new ASCExitListener() { @Override public void onGameExit() { //游戏自己的退出确认框 AlertDialog.Builder builder = new AlertDialog.Builder(ASCUnityContext.this); builder.setTitle("退出确认"); builder.setMessage("现在还早,要不要再玩一会?"); builder.setCancelable(true); builder.setPositiveButton("好吧", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { //这里什么都不用做 } }); builder.setNeutralButton("一会再玩", new DialogInterface.OnClickListener() { @SuppressLint("NewApi") public void onClick(DialogInterface dialog, int whichButton) { //退出游戏 ASCUnityContext.this.finish(); System.exit(0); } }); builder.show(); } }); } //支付接口 public void pay(String data){ final PayParams params = parsePayParams(data); ASCPlatform.getInstance().pay(this, params); } //SDK是否支持用户中心 public boolean isSupportAccountCenter(){ return ASCUser.getInstance().isSupport("showAccountCenter"); } //SDK是否支持退出确认框 public boolean isSupportExit(){ return ASCUser.getInstance().isSupport("exit"); } //SDK是否支持退出确认框 public boolean isSupportLogout(){ return ASCUser.getInstance().isSupport("logout"); } public boolean isSDKShowSplash(){ return ASCSDK.getInstance().isSDKShowSplash(); } //向Unity中发送消息 public void sendCallback(String name, String jsonParams){ if(jsonParams == null){ jsonParams = ""; } UnityPlayer.UnitySendMessage(CALLBACK_GAMEOBJECT_NAME, name, jsonParams); } private UserExtraData parseGameData(String str){ UserExtraData data = new UserExtraData(); try { JSONObject json = new JSONObject(str); data.setDataType(json.getInt("dataType")); data.setRoleID(json.getString("roleID")); data.setRoleName(json.getString("roleName")); data.setRoleLevel(json.getString("roleLevel")); data.setServerID(json.getInt("serverID")); data.setServerName(json.getString("serverName")); data.setMoneyNum(json.getInt("moneyNum")); String roleCreateTime = json.getString("roleCreateTime"); String roleLevelUpTime = json.getString("roleLevelUpTime"); if(!TextUtils.isEmpty(roleCreateTime.trim())){ data.setRoleCreateTime(Long.valueOf(roleCreateTime.trim())); } if(!TextUtils.isEmpty(roleLevelUpTime.trim())){ data.setRoleLevelUpTime(Long.valueOf(roleLevelUpTime.trim())); } data.setVip(json.optString("vip", "0")); } catch (JSONException e) { e.printStackTrace(); } return data; } private PayParams parsePayParams(String str){ PayParams params = new PayParams(); try{ JSONObject json = new JSONObject(str); params.setProductId(json.getString("productId")); params.setProductName(json.getString("productName")); params.setProductDesc(json.getString("productDesc")); params.setPrice(json.getInt("price")); params.setRatio(0);//该字段废弃不用 params.setBuyNum(json.getInt("buyNum")); params.setCoinNum(json.getInt("coinNum")); params.setServerId(json.getString("serverId")); params.setServerName(json.getString("serverName")); params.setRoleId(json.getString("roleId")); params.setRoleName(json.getString("roleName")); params.setRoleLevel(json.getInt("roleLevel")); params.setPayNotifyUrl(json.getString("payNotifyUrl")); params.setVip(json.getString("vip")); params.setExtension(json.getString("extension")); }catch(Exception e){ e.printStackTrace(); } return params; } public void onActivityResult(int requestCode, int resultCode, Intent data){ ASCSDK.getInstance().onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data); } public void onStart(){ ASCSDK.getInstance().onStart(); super.onStart(); } public void onPause(){ ASCSDK.getInstance().onPause(); super.onPause(); } public void onResume(){ ASCSDK.getInstance().onResume(); super.onResume(); } public void onNewIntent(Intent newIntent){ ASCSDK.getInstance().onNewIntent(newIntent); super.onNewIntent(newIntent); } public void onStop(){ ASCSDK.getInstance().onStop(); super.onStop(); } public void onDestroy(){ ASCSDK.getInstance().onDestroy(); super.onDestroy(); } public void onRestart(){ ASCSDK.getInstance().onRestart(); super.onRestart(); } private void tip(final String tip){ ASCSDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { //Toast.makeText(ASCUnityContext.this, tip, Toast.LENGTH_SHORT).show(); } }); } private void OnRate(){ try { String str = "market://details?id=" + ASCSDK.getInstance().getApplication().getPackageName(); Log.d("ASCSDK", "OnRate url:"+str); Intent localIntent = new Intent(Intent.ACTION_VIEW); localIntent.setData(Uri.parse(str)); ASCSDK.getInstance().getContext().startActivity(localIntent); } catch (Exception e) { // 打开应用商店失败 可能是没有手机没有安装应用市场 e.printStackTrace(); Toast.makeText(ASCSDK.getInstance().getContext().getApplicationContext(), "打开应用商店失败", Toast.LENGTH_SHORT).show(); // 调用系统浏览器进入商城 String url = "http://app.mi.com/detail/163525?ref=search"; openLinkBySystem(url); } } private void openLinkBySystem(String url) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); ASCSDK.getInstance().getContext().startActivity(intent); } } 说明: 其中,CALLBACK_GAMEOBJECT_NAME就是Unity中这个负责接收回调通知的GameObject的名称 此类包含了初始化SDK,登陆,登出,退出,支付,提交扩展数据方法。 ASCInitListener此接口为所有回调的监听接口。 onPayResult------支付回调(网游专用接口)。 onLoginResult------登陆结果回调。 onInitResult------初始化结果回调。 onSinglePayResult------单机支付结果回调。 还有一些登出,查询订单,视频回调等,详情看代码注解。 2. Untiy接入文档------Unity端 拷贝上面Android端生成的ascsdk_unitylib.jar到unity工程libs目录中。 拷贝ASCSDK的抽象层工程中的bin目录下生成的ascsdk3.jar拷贝到libs目录中。 在Unity中怎么来完成Android中相关接口的调用以及封装。 我们定义一个ASCSDKInterface的抽象单例类: public abstract class ASCSDKInterface{ public delegate void LoginSucHandler(ASCLoginResult data); public delegate void LogoutHandler(); private static ASCSDKInterface _instance; public LoginSucHandler OnLoginSuc; public LogoutHandler OnLogout; public static ASCSDKInterface Instance { get { if (_instance == null) { #if UNITY_EDITOR || UNITY_STANDLONE _instance = new SDKInterfaceDefault(); #elif UNITY_ANDROID _instance = new SDKInterfaceAndroid(); #elif UNITY_IOS _instance = new SDKInterfaceIOS(); #endif } return _instance; } } //初始化 public abstract void Init(); //登录 public abstract void Login(); //自定义登录,用于腾讯应用宝,QQ登录,customData="QQ";微信登录,customData="WX" public abstract void LoginCustom(string customData); //切换帐号 public abstract void SwitchLogin(); //登出 public abstract bool Logout(); //显示个人中心 public abstract bool ShowAccountCenter(); //上传游戏数据 public abstract void SubmitGameData(ASCExtraGameData data); //调用SDK的退出确认框,返回false,说明SDK不支持退出确认框,游戏需要使用自己的退出确认框 public abstract bool SDKExit(); //调用SDK支付界面 public abstract void Pay(ASCPayParams data); //SDK是否支持退出确认框 public abstract bool IsSupportExit(); //SDK是否支持用户中心 public abstract bool IsSupportAccountCenter(); //SDK是否支持登出 public abstract bool IsSupportLogout(); //去ASCServer获取游戏订单号,这里逻辑是访问游戏服务器,然后游戏服务器去ASCServer获取订单号 //并返回 public ASCPayParams reqOrder(ASCPayParams data) { //TODO 去游戏服务器获取订单号 //测试 data.orderID = "345435634534"; data.extension = "test"; return data; } } 有了这个抽象类,对于各个平台,我们需要分别实现该抽象类中的接口,从而间接地调用平台中的方法。对于Android平台,我们定义一个SDKInterfaceAndroid类: public class SDKInterfaceAndroid : ASCSDKInterface { private AndroidJavaObject jo; public SDKInterfaceAndroid() { using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { jo = jc.GetStatic<AndroidJavaObject>("currentActivity"); } } private T SDKCall<T>(string method, params object[] param) { try { return jo.Call<T>(method, param); } catch (Exception e) { Debug.LogError(e); } return default(T); } private void SDKCall(string method, params object[] param) { try { jo.Call(method, param); } catch (Exception e) { Debug.LogError(e); } } //这里Android中,在onCreate中直接调用了initSDK,所以这里就不用调用了 public override void Init() { //SDKCall("initSDK"); } public override void Login() { SDKCall("login"); } public override void LoginCustom(string customData) { SDKCall("loginCustom", customData); } public override void SwitchLogin() { SDKCall("switchLogin"); } public override bool Logout() { if (!IsSupportLogout()) { return false; } SDKCall("logout"); return true; } public override bool ShowAccountCenter() { if (!IsSupportAccountCenter()) { return false; } SDKCall("showAccountCenter"); return true; } public override void SubmitGameData(ASCExtraGameData data) { string json = encodeGameData(data); SDKCall("submitExtraData", json); } public override bool SDKExit() { if (!IsSupportExit()) { //return false; } SDKCall("exit"); return true; } public override void Pay(ASCPayParams data) { string json = encodePayParams(data); SDKCall("pay", json); } public override bool IsSupportExit() { return SDKCall<bool>("isSupportExit"); } public override bool IsSupportAccountCenter() { return SDKCall<bool>("isSupportAccountCenter"); } public override bool IsSupportLogout() { return SDKCall<bool>("isSupportLogout"); } private string encodeGameData(ASCExtraGameData data) { Dictionary<string, object> map = new Dictionary<string, object>(); map.Add("dataType", data.dataType); map.Add("roleID", data.roleID); map.Add("roleName", data.roleName); map.Add("roleLevel", data.roleLevel); map.Add("serverID", data.serverID); map.Add("serverName", data.serverName); map.Add("moneyNum", data.moneyNum); return MiniJSON.Json.Serialize(map); } private string encodePayParams(ASCPayParams data) { Dictionary<string, object> map = new Dictionary<string, object>(); map.Add("productId", data.productId); map.Add("productName", data.productName); map.Add("productDesc", data.productDesc); map.Add("price", data.price); map.Add("buyNum", data.buyNum); map.Add("coinNum", data.coinNum); map.Add("serverId", data.serverId); map.Add("serverName", data.serverName); map.Add("roleId", data.roleId); map.Add("roleName", data.roleName); map.Add("roleLevel", data.roleLevel); map.Add("vip", data.vip); map.Add("orderID", data.orderID); map.Add("extension", data.extension); return MiniJSON.Json.Serialize(map); } } 接下来,我们就定义一个专门负责回调的脚本: public class ASCSDKCallback : MonoBehaviour { private static ASCSDKCallback _instance; private static object _lock = new object(); //初始化回调对象 public static ASCSDKCallback InitCallback() { UnityEngine.Debug.LogError("Callback->InitCallback"); lock (_lock) { if (_instance == null) { GameObject callback = GameObject.Find("(ascsdk_callback)"); if (callback == null) { callback = new GameObject("(ascsdk_callback)"); UnityEngine.Object.DontDestroyOnLoad(_instance); _instance = callback.AddComponent<ASCSDKCallback>(); } else { _instance = callback.GetComponent<ASCSDKCallback>(); } } return _instance; } } //初始化成功回调 public void OnInitSuc() { //一般不需要处理 UnityEngine.Debug.LogError("Callback->OnInitSuc"); } //登录成功回调 public void OnLoginSuc(string jsonData) { UnityEngine.Debug.LogError("Callback->OnLoginSuc"); ASCLoginResult data = parseLoginResult(jsonData); if (data == null) { UnityEngine.Debug.LogError("The data parse error." + jsonData); return; } if (ASCSDKInterface.Instance.OnLoginSuc != null) { ASCSDKInterface.Instance.OnLoginSuc.Invoke(data); } } //切换帐号回调 public void OnSwitchLogin() { UnityEngine.Debug.LogError("Callback->OnSwitchLogin"); if (ASCSDKInterface.Instance.OnLogout != null) { ASCSDKInterface.Instance.OnLogout.Invoke(); } } //登出回调 public void OnLogout() { UnityEngine.Debug.LogError("Callback->OnLogout"); if (ASCSDKInterface.Instance.OnLogout != null) { ASCSDKInterface.Instance.OnLogout.Invoke(); } } //支付回调,网游不需要实现该接口,该接口用于单机游戏 public void OnPaySuc(string jsonData) { //Nothing... } private ASCLoginResult parseLoginResult(string str) { object jsonParsed = MiniJSON.Json.Deserialize(str); if (jsonParsed != null) { Dictionary<string, object> jsonMap = jsonParsed as Dictionary<string, object>; ASCLoginResult data = new ASCLoginResult(); if (jsonMap.ContainsKey("isSuc")) { data.isSuc = bool.Parse(jsonMap["isSuc"].ToString()); } if (jsonMap.ContainsKey("isSwitchAccount")) { data.isSwitchAccount = bool.Parse(jsonMap["isSwitchAccount"].ToString()); } if (jsonMap.ContainsKey("userID")) { data.userID = jsonMap["userID"].ToString(); } if (jsonMap.ContainsKey("sdkUserID")) { data.sdkUserID = jsonMap["sdkUserID"].ToString(); } if (jsonMap.ContainsKey("username")) { data.username = jsonMap["username"].ToString(); } if (jsonMap.ContainsKey("sdkUsername")) { data.sdkUsername = jsonMap["sdkUsername"].ToString(); } if (jsonMap.ContainsKey("token")) { data.token = jsonMap["token"].ToString(); } return data; } return null; } } 到这里,ASCSDK在Unity中的封装基本就算完成了,接下来,我们就来测试下接口的调用。我们用UGUI建立一个建立一个简单的面板,然后包含一个登录按钮和支付按钮,然后通过绑定一个ClickObject.cs脚本来简体按钮的响应事件: public class ClickObject : MonoBehaviour { // Use this for initialization private Text txtState; void Start () { ASCSDKCallback.InitCallback(); GameObject loginObj = GameObject.Find("BtnLogin"); Button btnLogin = loginObj.GetComponent<Button>(); btnLogin.onClick.AddListener(delegate() { OnLoginClick(); }); GameObject payObj = GameObject.Find("BtnPay"); Button btnPay = payObj.GetComponent<Button>(); btnPay.onClick.AddListener(delegate() { OnPayClick(); }); GameObject stateObj = GameObject.Find("TxtState"); txtState = stateObj.GetComponent<Text>(); ASCSDKInterface.Instance.OnLoginSuc = delegate(ASCLoginResult result) { OnLoginSuc(result); }; ASCSDKInterface.Instance.OnLogout = delegate() { OnLogout(); }; } void Update() { if (Input.GetKeyUp(KeyCode.Escape)) { if (!ASCSDKInterface.Instance.SDKExit()) { //TODO 退出确认框 Application.Quit(); } } } void OnLoginSuc(ASCLoginResult result) { if (!result.isSuc) { txtState.text = "登录失败"; return; } if (result.isSwitchAccount) { txtState.text = "切换帐号成功:" + result.token; } else { txtState.text = "登录成功:" + result.token; } } void OnLogout() { txtState.text = "未登录"; } void OnLoginClick() { ASCSDKInterface.Instance.Login(); } void OnPayClick() { ASCPayParams data = new ASCPayParams(); data.productId = "1"; data.productName = "元宝"; data.productDesc = "购买100元宝,赠送20元宝"; data.price = 100; data.buyNum = 1; data.coinNum = 300; data.serverId = "10"; data.serverName = "地狱之恋"; data.roleId = "asc_24532452"; data.roleName = "麻利麻利吼"; data.roleLevel = 15; data.vip = "v15"; data = ASCSDKInterface.Instance.reqOrder(data); ASCSDKInterface.Instance.Pay(data); } } 最后说明:我们将提供unity的工程的demo,具体可以参考我们demo,此文档暂时没有提供广告接口的说明,原理与login支付一样,调用我给你们提供的方法就可以,具体以我们给的demo为准。有任何问题可以联系我们的商务人员。

优秀的个人博客,低调大师

Android 使用 FFmpeg命令行(多包)

1. 新建项目,导入.so文件 将之前编译生成的多个.so文件及inclulde文件夹下的头文件拷贝到/app/libs文件夹下,拷贝后目录结果如下: 图1.png 2. 配置/app/src/main目录下新建jni文件夹 图2.png 3. 创建FFmpegCmd.java类 package com.mazaiting.ffmpegcmdtest; /** * FFmpeg命令行操作 * @author mazaiting * @date 2018/1/12 */ public class FFmpegCmd { static { System.loadLibrary("avcodec-57"); System.loadLibrary("avdevice-57"); System.loadLibrary("avfilter-6"); System.loadLibrary("avformat-57"); System.loadLibrary("avutil-55"); System.loadLibrary("swresample-2"); System.loadLibrary("swscale-4"); System.loadLibrary("FfmpegCmd"); } public static int execute(String[] commands) { return run(commands); } public native static int run(String[] commands); } 4. 配置/app/build.gradle文件 1). 在android节点下的defaultConfig目录下新增 ndk { moduleName "ffmpegcmd" abiFilters "armeabi" } 2). 在android节点下新增,如果已有则替换这段 sourceSets { main { jniLibs.srcDirs = ['src/main/libs'] jni.srcDirs=[] } } 5. 生成jni的头文件 javah命令配置, 运行命令完成后,在jni文件夹下生成com_mazaiting_ffmpegcmdtest_FFmpegCmd.h文件 图3.png 6. 配置jni目录 将ffmpeg源码中的ffmpeg.h, ffmpeg.c, ffmpeg_opt.c, ffmpeg_filter.c,cmdutils.c, cmdutils.h, cmdutils_common_opts.h,config.h 赋值到jni目录下,并在 jni 目录新建文件 Android.mk Application.mk com_mazaiting_ffmpegcmdtest_FFmpegCmd.c。 7. 修改ffmpeg源码 1). 编辑ffmpeg.c,把 int main(int argc, char **argv) 改名为 int run(int argc, char **argv) 编辑ffmpeg.h, 在文件末尾(在#endif前面)添加函数申明: int run(int argc, char **argv) 2). 编辑cmdutils.c中的exit_program函数,删掉函数中原来的内容, 添加 return ret;并修改函数的返回类型为int。 长这样: int exit_program(int ret) { return ret; } 编辑cmdutils.h中exit_program的申明,把返回类型修改为int。 int exit_program(int ret); 8. 其他文件 1). com_mazaiting_ffmpegcmdtest_FFmpegCmd.c #include "com_mazaiting_ffmpegcmdtest_FFmpegCmd.h" #include "ffmpeg.h" #include <android/log.h> #define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"ffmpeg",FORMAT,##__VA_ARGS__); #define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"ffmpeg",FORMAT,##__VA_ARGS__); JNIEXPORT jint JNICALL Java_com_mazaiting_ffmpegcmdtest_FFmpegCmd_run (JNIEnv *env, jclass cls, jobjectArray commands) { int argc = (*env)->GetArrayLength(env, commands); char *argv[argc]; LOGE("Kit argc %d\n", argc); int i; for (i = 0; i < argc; i++) { jstring js = (jstring)(*env)->GetObjectArrayElement(env, commands, i); argv[i] = (char *) (*env)->GetStringUTFChars(env, js, 0); LOGE("Kit argv %s\n", argv[i]); } return run(argc, argv); } 2). Android.mk LOCAL_PATH := $(call my-dir) # FFmpeg library include $(CLEAR_VARS) # 打印当前路径 $(warning $(LOCAL_PATH)) # .so文件名称,去除前缀lib和-后的内容 LOCAL_MODULE := avcodec # .so文件 LOCAL_SRC_FILES := libavcodec-57.so # 已编译好的库使用PREBUILT_SHARED_LIBRARY include $(PREBUILT_SHARED_LIBRARY) # FFmpeg library include $(CLEAR_VARS) LOCAL_MODULE := avdevice LOCAL_SRC_FILES := libavdevice-57.so include $(PREBUILT_SHARED_LIBRARY) # FFmpeg library include $(CLEAR_VARS) LOCAL_MODULE := avfilter LOCAL_SRC_FILES := libavfilter-6.so include $(PREBUILT_SHARED_LIBRARY) # FFmpeg library include $(CLEAR_VARS) LOCAL_MODULE := avformat LOCAL_SRC_FILES := libavformat-57.so include $(PREBUILT_SHARED_LIBRARY) # FFmpeg library include $(CLEAR_VARS) LOCAL_MODULE := avutil LOCAL_SRC_FILES := libavutil-55.so include $(PREBUILT_SHARED_LIBRARY) # FFmpeg library include $(CLEAR_VARS) LOCAL_MODULE := swresample LOCAL_SRC_FILES := libswresample-2.so include $(PREBUILT_SHARED_LIBRARY) # FFmpeg library include $(CLEAR_VARS) LOCAL_MODULE := swscale LOCAL_SRC_FILES := libswscale-4.so include $(PREBUILT_SHARED_LIBRARY) # Program # module名称 include $(CLEAR_VARS) LOCAL_MODULE := FfmpegCmd # module中的源文件 LOCAL_SRC_FILES := com_mazaiting_ffmpegcmdtest_FFmpegCmd.c ffmpeg.c ffmpeg_opt.c cmdutils.c ffmpeg_filter.c # ffmpeg源码路径 LOCAL_C_INCLUDES += C:/Users/Administrator/Desktop/ffmpeg-3.3.6 LOCAL_LDLIBS := -llog -lz # 链接的动态库文件 LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil swresample swscale # 编译生成的库使用BUILD_SHARED_LIBRARY include $(BUILD_SHARED_LIBRARY) 3). Application.mk APP_MODULES := FfmpegCmd APP_ABI := armeabi APP_PLATFORM := android-14 # 去除原子性编译 APP_LDFLAGS := -latomic 9. 编译FfmpegCmd.so文件 编译之前先将/app/libs文件夹内的ffmpeg中拷贝的.so文件拷贝到jni文件夹一份,此时jni文件夹内的所有文件如图4,使用ndk-build命令编译(图5)。 图4.png 图5.png 10. 编译成功 编译成功后在main目录下生成libs和obj文件夹,将/libs/armeabi/下的libFfmpegcmd.so或者/obj/local/armeabi/objs/下的libFfmpegcmd.so文件复制到/app/libs/armeabi/目录下,此时在java文件中即可成功使用ffmpeg。 图6.png 11. 使用 1). 在AndroidManifest.xml添加权限 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 2). activity_main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.mazaiting.ffmpegcmdtest.MainActivity"> <Button android:onClick="start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="合成"/> </RelativeLayout> 3). MainActivity.java public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private boolean isRun = false; /**视频源路径*/ private String videoUrl = "/storage/emulated/0/input.mp4"; /**图片路径*/ private String imageUrl = "/storage/emulated/0/image.png"; /**视频输出路径*/ private String outputUrl = "/storage/emulated/0/output.mp4"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void start(View view){ if (!isRun) { new Thread(mRunnable).start(); isRun = true; } else { Toast.makeText(this, "正在运行", Toast.LENGTH_SHORT).show(); } } /** * 添加水印任务 */ Runnable mRunnable = new Runnable() { @Override public void run() { String[] commands = new String[10]; commands[0] = "ffmpeg"; commands[1] = "-i"; commands[2] = videoUrl; commands[3] = "-i"; commands[4] = imageUrl; commands[5] = "-filter_complex"; commands[6] = "overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2"; commands[7] = "-codec:a"; commands[8] = "copy"; commands[9] = outputUrl; Log.e(TAG, "run: 开始执行"); FFmpegCmd.execute(commands); Log.e(TAG, "run: 执行结束"); isRun = false; } }; } 12. 运行结果 图7.png

优秀的个人博客,低调大师

php的ts和nts安装包

2017-12-29 15:17:05 星期五 翻译一下PHP对 ts , nts 的解释 官网说明地址:http://windows.php.net/download (windows下载页左侧) TS refers to multithread capable builds. NTS refers to single thread only builds. Use case for TS binaries involves interaction with a multithreaded SAPI and PHP loaded as a module into a web server. For NTS binaries the widespread use case is interaction with a web server through the FastCGI protocol, utilizing no multithreading (but also for example CLI). 一段代码需要经过 `编译`和 `连接` 等操作才能成为最终的可执行文件(二进制文件) 而单词, compile、build分别对应编译和连接这两个过程。 线程安全(TS) 指的是编译连接时指定启用多线程安全扩展, 使PHP支持多线程, 非线程安全(NTS)指的是单线程build; 线程安全的使用场景是, 使用多线程的SAPI进行交互并且PHP作为一个web服务器的模块被加载 对非线程安全来说, 最广泛的应用场景是通过并未使用多线程的 FastCGI 协议跟一个web服务器进行交互 (命令行环境下也是非线程安全的模式)

优秀的个人博客,低调大师

接口测试之Fiddler+APP抓包

Fiddler简介: Fiddler是强大且好用的Web调试工具之一,它能记录客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数 据。 Fiddler 的运行机制其实就是本机上监听8888端口的HTTP代理。 对于PC端Fiddler启动的时候默认IE的代理设为了127.0.0.1:8888,而其他浏览器是需要手动设置的,所以如果需要监听PC端 Chrome网络请求,将其代理改为127.0.0.1:8888就可以监听数据了,手机端按照下面的设置即可完成整个系统的http代理。 一、下载神器Fiddler,下载链接:fiddler2.com/get-fiddler下载完成之后,傻瓜式的安装一下OK了! Fiddler桌面快捷方式 二、设置Fiddler 打开Fiddler, Tools-> Fiddler Options (配置完后记得要重启Fiddler) 选中"Decrpt HTTPS traffic", Fiddler就可以截获HTTPS请求 配置HTTPS请求 选中"Allow remote computers to connect". 是允许别的机器把HTTP/HTTPS请求发送到Fiddler上来。记住这个端口号是:8888 配置HTTP/HTTPS请求权限 三、设置Android手机 首先获取PC的ip地址:命令行中输入:ipconfig,获取ip地址。这时候我就拿到了电脑IP地址和端口号了 PC端IP地址 下面来对Android手机进行代理设置,本人使用的是小米5S 首先,要确定一下手机和PC是连接在同一个局域网中 进入手机的设置->点击进入WLAN设置->选择连接到的无线网,点右边的箭头(有的手机是长按弹出选项框):如图所示: 设置代理 代理这一行,选择:手动 选择修改网络配置: 1)配置主机名:与主机电脑IP地址保持一致 2)端口号:8888 设置代理 点击保存。这样就将我们的手机设置成功了。 四、打开要测试的APP,然后打开电脑上的fiddler界面,本人在手机端打开的是“简书APP”。如下图 抓简书APP 这样就抓取Android移动端的数据包成功了,这个对于我们后面进行网络数据请求的调试有很大的帮助,我们可以通过这个方法来判断我们请求网络是否成功! 注:一般http请求,不用安装安全证书;如果是https的请求,设置代理后,会无法访问,这时候就需要安装安全证书了 五、下载Fiddler的安全证书 使用手机的浏览器打开:http://192.168.2.204:8080, 点"FiddlerRoot certificate" 然后安装证书,如图: 下载安全证书 六、截取HTTPS请求 1.下载安装证书生成器 证书地址:http://www.telerik.com/docs/default-source/fiddler/addons/fiddlercertmaker.exe?sfvrsn=2 2.生成证书保存至电脑桌面(Tools->Options->HTTPS->Actions->Export Root Certificate to Desktop) 生成证书 FiddlerRoot.cer 证书 3.将桌面的FiddlerRoot.cer(生成的证书)放到手机中安装(通过USB数据线或者SD卡导入) 安装证书 4.查看抓取的请求类型(结果) 请求结果 好了,小伙伴们,下一步就该学习学习该怎么分析抓到的数据了。。。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册