2018-12-12 16:31:29 qq_40480758 阅读数 139
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

在学习Android的过程中,学到网络相关的东西时,没有服务端接口很是困扰,但是对服务端的知识还不是很了解,所以用了moco.jar来模拟服务端接口。

我主要讲一下我的项目中用到的接口形式吧。具体的一些教程可以参考这篇文章=>https://blog.csdn.net/sanjay_f/article/details/50204883

下面来看具体步骤

先下载这个文件moco.jar(或者留言我私发),放在桌面或者随便哪个盘里  ,你记得路径就行,我是直接放在了E盘 。

然后打开记事本复制这么几行文本

[
	{
		"request":
		{
			"uri": "/getJson",
			"method":"get"
		},
		"response":
		{
			"status":200,
			"headers":
			{
				"content-type":"application/json"
			},
			"json":
			{
				"code":200,
				"msg":"",
				"data":
				[
				{
					"client_username":"lisi",
					"client_name":"李四",
					"client_phone":"1223344",
					"client_address":"马鞍山"
				},
				{
					"client_username":"zhangsan",
					"client_name":"张三",
					"client_phone":"1111111",
					"client_address":"合肥"
				}
			]
			}
		}
	}
]

 点击保存,也是随便放哪,记得路径就行。这里我踩了个雷。。。

然后打开cmd,输入这样一串命令java -jar E:\moco-runner-0.10.2-standalone.jar start -p 8081 -c E:\json\data.json

将我的命令中的文件修改成你的文件的路径,8081是创建的端口号,理论上是随便的,只要端口号没有被占用就行。点击回车,你就会看见这样的回复

这样就算成功了! 我之前由于列表里面有中文,然后 就报UTF-8格式错误,我将记事本里面的格式改成中文GB2312也不行,然后我就用NotePadd++打开,然后将编码格式改为转为UTF-8编码,之后就可以了。

成功之后可以在浏览器里面试一下输入http://localhost:8081/getJson

 现在我们在Android里面试一下这个模拟接口

public class UrlDemoActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_url_demo);
        Uri webViewUri = Uri.parse("http://192.168.43.210:8081/getJson");
        Intent intent = new Intent(Intent.ACTION_VIEW,webViewUri);
        startActivity(intent);
    }
}

那个端口号改成自己的ip地址就行,我是用的是真机调试, 所以有点麻烦,先用手机给电脑开热点,然后在cmd里面输入ipconfig获取主机ip地址

运行程序,你会发现这个接口是可用的,至于你们想在接口里面写什么,获取数据之后怎么处理,就要看你自己了。

2017-11-06 18:56:57 u014746965 阅读数 887
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

情景描述:本人是java后端开发,配合Android移动端开发  1.支付接口;  2.订单支付状态查询接口。

问题:接口响应报文结构,自己设计出来后,总是和移动端需要的有很大的出入。

解决:

接口1:支付接口

支付只是一次请求,不包含任何业务参数

移动端需要信息:请求是否成功;如果失败,失败原因是什么。 

响应报文核心字段:

retcode:SUCCESS/FAIL

retmsg: 支付成功/缺乏必须参数等。


可能的响应报文:

1.支付成功

retcode:SUCCESS

retmsg: 支付成功

2.通信失败

retcode:FAIL

retmsg: 网络断开

3.通信成功,交易失败

retcode:FAIL

retmsg: 账户余额不足

  说明:此处的失败是通信失败(网络断开 和 请求失败(余额不足)的并集,但是并不需要区分开,因为移动端不需要区分,他只关注支付成功或失败。


接口2:支付状态查询接口

支付状态查询:不仅是一次请求,同时需要包含业务参数:支付状态。

移动端需要信息:请求是否成功;如果成功了,业务参数:支付状态具体值。

响应报文核心字段:

retcode:SUCCESS/FAIL

retmsg: 查询成功/查询失败等。

payState: 0:支付成功 1支付失败


可能的响应报文:

1.通信成功且支付成功

retcode:SUCCESS

retmsg: 查询成功

payState:0


2.通信成功但支付失败

retcode:SUCCESS

retmsg: 查询成功

payState:1


3.通信失败

retcode:FAIL

retmsg: 网络断开

  说明:此处的失败只是代表通信失败(网络断开) ,只有通信成功了,再去查看 请求成功与否,从而获取需要的业务参数:比如此处的支付状态。


事后反思:

      1.换位思考:明确这两个接口是提供给移动端使用:如何设计才能让移动端高效、快捷地拿到他想要的信息。不要用自己java后端开发的思维定势去设计。

      2.与他人合作开发观照情绪,别被情绪拖着走:渐渐发现,IT工作碰到的很多问题,不良的情绪总是可以导致工作效率低下,本来会做的事情,却做的很吃力。

     比如:这次合作开发,移动端开发者:嗓门很大,气势咄咄逼人。虽然理智知道他的修改建议很正确,可是自己心里有个魔鬼跳出来:他谁啊!为啥要听他的!导致自己很大的精力,被嗔怒的情绪所消耗。或者,开发中碰到一个完全没有接触过的东西,本人有时候会对自己不能掌控的东西,有种莫名的恐惧。这个恐惧的情绪,导致你不敢大步向前走,奋起直前解决问题。(果真生活中处处是修行啊!)

    

      生活所感,仅此小记



2013-03-15 20:31:41 zhaoweiqiang601 阅读数 1029
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

 android应用程序如何访问restful接口

建立能够访问restful接口的android应用程序,需要用到类包含在android,jar文件中,它的位置在D:\androidSDK-r21\platforms\android-8\android.jar。

一、rest post

1、建立客户端 HttpClient对象

2、建立访问方式 HttpPost对象

3、组建访问参数 JSONObject对象

4、设置请求头和请求实体 setHeader() setEntity()

5、建立访问返回值对象 HttpResponse

6、解析返回字符串 EntityUtils.toString()

代码如下:

try{

  HttpClient client = new DefaultHttpClient();

  HttpPost requst = new HttpPost("www.baidu.com");

  JSONObject paramJson = new JSONObject();

  paramJson.put("param", param);

  //可根据服务端要求情况设置请求头

  request.setHeader("Accept","text/html");

  request.setEntity(new StringEntity(Base64.encodeToString(paramJson.toString.getBytes(),0)));

  HttpResponse response = client.execute(request);

  result = EntityUtils.toString(response.getEntity());

  resutl = new String(Base64.decode(result.getBytes(),0));

}catch(Exception e){

  e.printStachTrace();

}

2016-12-15 16:29:01 u013296766 阅读数 2048
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

android 常用api 接口签名验证

从登录注册说起该验证的全部过程:

1.android 登录时一般是这样:

loginData.put("name", userNameText.toString());
loginData.put("password", passWordText.toString());
loginData.put("platform", "android");
//同步方式
try {
    //调用登录接口网络请求
    JSONObject response = okHttpManager.post(login_url, loginData);

2.在客户端在登录成功时 记录 以下信息

//保存用户信息, 常用的单独保存
PreferenceManager pm = PreferenceManager.getInstance();
pm.setString("user_id", loginDetail.getString("user_id"));
pm.setString("app_token", loginDetail.getString("app_token"));
pm.setString("app_ticket", loginDetail.getString("ticket"));
pm.setString("userinfo", loginDetail.toString());

那服务器端返回的app_token 以及ticket 是怎么产生的呢 有什么作用呢?????

3.服务器端 接收到登录信息后应该是这样处理:
//生成token
$app_token  = empty($userInfo['app_token']) ? $this->genAppToken($retParams['name'], $retParams['platform']) : '';

这个时候将更新users表 的 app_token字段。

//生成ticket
$ticket = $this->genAppToken($userInfo['user_id'], $userInfo['mobile']);

这个时候判断check_online表 有没有该条数据,如果没有将其插入到online_user表中,该表的设计应该是这样:

id | user_id | ticket | expire_time | platform |

(这个表的作用是记录成功登录 也就是正在线上的表,如果登出的话就应该将这条记录删除)

并将(userid跟ticket)做索引
(所以判断用户是否在线 可以通过user_id 或者通过ticket 做判断)

这个genAppToken 可以用md5 或者sha 都行,反正就是单向加密的都可以,这个时候可以进行api 接口签名验证工作

客户端逻辑跟服务器端逻辑相似

服务器端如下:

api的话需要区分是否需要登录的接口 所以这块需要做到免验证判断:如下可以实现

$loginArr  = array('login', 'register', 'mobile_verifycode_login', 'forget_password', 'send_email', 'createSMS', 'check_exis    ts', 'notifySync', 'wx_auth_register','wx_auth_login');
 60             if (!in_array($method, $loginArr)) {
 61                 $this->load->model(array('User_model'));
 62                 $operator      = $this->isLogin();
 63                 $this->operator = array(
 64                     'user_id' => (int)$operator['user_id'], 'ticket' => $operator['ticket']
 65                 );
 66             }

简单的对数组进行添加就可以实现添加免验证的接口,根据上面做的online_user表的工作,很显然能知道 判断一个用户是否已经登陆 只要根据他的user_id 或者ticket就能够判断,如果不在线 则跳到登录页

在免接口验证中,显然不能通过ticket 来进行对用户的区分,所以我们用了sign签名的方式来解决API签名的一些问题

  • 请求参数是否被篡改
  • 请求来源是否合法
  • 请求是否具有唯一性

所以加签策略可以如下所示:

$sign  = $params['sign'];
269         $timestamp  = $params['timestamp'];
270         $secret = “123sqweqweq“;    //换成自己的secret
271


272         $app_ticket = $this->input->get_post(COOKIE_TICKET);
273         $app_token  = '';
274         if (!empty($app_ticket)) {
275             //获取app_token
276             $cacheData  = $this->ciredis->hGetAll('online:ticket:' . $app_ticket);
277             $userInfo  = $this->User_model->get(array('user_id' => $cacheData['user_id']));
278             $app_token = !empty($userInfo['app_token']) ? $userInfo['app_token'] : APPSECRET;
279         }

客户端往服务器端传参数的时候,对其是否传app_ticket 做判断,如果有 则用这个app_ticket 对表或者缓存中去app_token (要注意 app_ticket 跟app_token不能放在一个缓存或一个表中,还是需要user_id做关联)

//过滤掉sign
285         unset($params['sign'], $params['s']);
286         //排序
287         ksort($params);
288         reset($params);
289
290         //拼接字符串
291         $arg = "";
292         while (list ($key, $val) = each($params)) {
293             $arg .= $key . "=" . $val . "&";
294         }
295         $arg    = rtrim($arg,'&');

先保存起来用户传递的签名,需要服务器端用自己的方法生成签名,然后跟客户端传来的签名做匹配,如果成功就通过,否则就报签名错误

一般服务器端验证签名步骤都是这样:

1.先排序ksort

2.拼接字符串

foreach($params as $key=>$val) {
     $arg .= $key.”=“.$val.”&”;
}

3.然后对拼接完的字符串再加一段随机数进行md5 或者 sha 加签,类似如下:

key = "123aqwqw";
$newSign = sha1($arg."$key");

这个时候得到的newSign 就是服务器所生成的sign(当然其中的加签字符串可以设置长些复杂些);
那这个newSign 跟客户端传过来的sign 做匹配 。相同则通过.

这样做的好处如下:

newSign 是根据所传递的参数进行加密的 所以 当其他人更改参数的时候,服务器端产生的newSign 必定与客户端传递的sign 不同,签名则不匹配
这个时候 就会有人问 如果我劫持了客户端的代码 同时获取了客户端的加签程序,不就可以更改客户端的sign了吗。

是这样的,所以android 经常使用jni 用c写一套加签的流程,这块代码是反编译不能获取不到的(这块代码是编译到so 文件中的),所以保证了客户端的代码安全

客户端代码如下:

secret  = PreferenceManager.getInstance().getString("app_token");
ShowLog.e(url);
addTicketToParams(params);
buildSign(params);

在网络请求的地方进行加ticket 加 sign(网络请求这块必须要做成公共调用,这样才能实现对接口访问的统一,可以做成单例模式。)

secret 作用是获取登录那会保存的app_token,
addTicketToParams 用来对params 进行加入ticket ,这个ticket 也是使用登录保存的ticket

重点在buidlSign这个部分。

params.put("timestamp", Long.toString(timestamp));
params.put("appsecret", secret);

Map<String, String> sortedParams        = new TreeMap<String, String>(params);
Set<Map.Entry<String, String>> entries  = sortedParams.entrySet();

StringBuffer buffer = new StringBuffer();
byte[] bytes    = null;
try {
    for (Map.Entry<String, String> entry : entries) {
        if (buffer.length() > 0) {
            buffer.append("&");
        }

        buffer.append(entry.getKey()).append("=").append(entry.getValue());

获取时间戳以及获取之前的secret 也就是app_token
然后也跟服务器端一样 遍历并挨个加=以及& 然后这时候加入jni 的编写的c语言程序加参
跟服务器端逻辑类似 只是用c 来实现服务器端php语言的实现效果
这个时候会返回一个字符串sign,然后

arams.remove("appsecret");
ShowLog.e(params.toString());
params.put("sign", doencrypt(buffer.toString()));
ShowLog.e(params.get("sign"));

将这个字符串加入sign 并与服务器端交互

这就是整个API接口签名验证的整个过程。

这块要注意的点在于不管是需要验证还是免验证的接口 必须让app_ticket 以及app_token 成对出现(要么都有 要么都没有)

2019-04-11 15:40:33 weixin_40998254 阅读数 761
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

 

近几年随着HTML5的功能越来越强大,H5页面的性能虽然稍差,单其灵活性很高,更新页面成本比原生小很多,一个页面可以被android和ios同时使用开发成本也比较低,所以移动端的开发已经不是单单的原生开发了,于是乎这就避免不了会进行Android和H5的交互。


一、H5调用android接口。

js 中调用Android的方法

    //H5中调用Android的方法
    function myOnclick(){
        //调用android本地方法 ,方法由Android提供 (具体对象名和方法待定,可变更)
        mobile.callAndroid("给Android传递的数据");
    }

 android给webView添加js接口

    //设置编码
    mWebView.getSettings().setDefaultTextEncodingName("utf-8");
    //支持js
    mWebView.getSettings().setJavaScriptEnabled(tr
    //设置本地调用对象及其接口
    //第一个参数为实例化自定义的接口对象  第二个参数为提供给JS端调用使用的对象名
    mWebView.addJavascriptInterface(new Contact
        @JavascriptInterface    //必须加的注解
        @Override
        public void openActivityByPath(String path) {//android给H5开的接口
                Intent intent = new Intent();
                intent.setClassName(mActivity, path);
                mActivity.startActivity(intent);
            }
    }, "mobile");

     //定义接口,提供给JS调用
    interface Contact {
        @JavascriptInterface
        void callAndroid(String phone);

    }


二、android调用H5接口。

js给android提供的接口

     //H5给Android提供的方法
    function callH5(data){
        document.getElementById("result").innerHTML="result success for Android to:"+data;
    }

android在点击事件中调用js接口 

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //Android调用Js方法
            mWebView.loadUrl("javascript:callH5('Android给H5传递的参数')");
        }
    });


三、android接口简单整理。

如果js接口过多会导致对webView的配置过长,影响代码的可读性和维护性,可以把给h5提供的接口都提取到一个类里,在webView 的配置中这样代码就清晰了很多。

AndroidJsUtils mAndroidJsUtils = new AndroidJsUtils(DoWebViewActivity.this);
mWebView.addJavascriptInterface(mAndroidJsUtils, "mobile");

 接口类

public class AndroidJsUtils implements Serializable {

    private BaseActivity mActivity; //工程的baseActivity

    public AndroidJsUtils(BaseActivity activity) {
            this.mActivity = activity;
    }

    /**
     * 打开任意页面
     * @param path 页面的完整路径例如:"com.xiaoxiao9575.demo.activity.DemoActivity"
     */
    @JavascriptInterface
    public void openActivityByPath(String path) {
        Intent intent = new Intent();
        intent.setClassName(mActivity, path);
        mActivity.startActivity(intent);
    }

}


四、WebView统一设置。

如果项目中有多个页面都用到了webView,各自配置维护起来就比较麻烦了,可以采用下面的方式统一配置。

/**
 * author: xiaoxiao9575
 * email:  xiaoxiao9575@126.com
 * csdn:   https://blog.csdn.net/weixin_40998254
 * createTime:  2019/4/11 10:09 AM
 */
public class MyBaseWebView extends WebView {

    private AndroidJsUtils mAndroidJsUtils;

    public MyBaseWebView(Context context) {
        super(context);
    }

    public MyBaseWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyBaseWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @SuppressLint("SetJavaScriptEnabled")
    public void initWebViewSetting(Activity activity){
        final WebSettings mWebSettings = this.getSettings();
        mWebSettings.setJavaScriptEnabled(true);
        this.setOverScrollMode(View.OVER_SCROLL_NEVER);
        mWebSettings.setDefaultTextEncodingName("utf-8");
        mWebSettings.setUseWideViewPort(true);
        mWebSettings.setLoadWithOverviewMode(true);
        mWebSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        mWebSettings.setDomStorageEnabled(true);
        mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        mWebSettings.setNeedInitialFocus(false);
        mWebSettings.setAllowFileAccess(true);
        mWebSettings.setAppCacheEnabled(true);
        mWebSettings.setAllowFileAccessFromFileURLs(true);
        mWebSettings.setDatabaseEnabled(true);
        String dbPath = activity.getDir("database", Context.MODE_PRIVATE).getPath();
        mWebSettings.setDatabasePath(dbPath);
        mWebSettings.setAppCachePath(dbPath);
        mWebSettings.setAppCacheMaxSize(5 * 1024 * 1024);
        mWebSettings.setGeolocationEnabled(true);
        mWebSettings.setGeolocationDatabasePath(dbPath);
        //不显示webview缩放按钮
        mWebSettings.setDisplayZoomControls(false);

        if (Build.VERSION.SDK_INT >= 21) {
            mWebSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }

        mAndroidJsUtils = new AndroidJsUtils(activity);
        this.addJavascriptInterface(mAndroidJsUtils, "mobile");

    }

}

 

没有更多推荐了,返回首页