月度归档: 2021 年 10 月

iOS逆向—-Mac m1芯片检测

由于Apple更新了m1芯片的Mac,导致iOS程序可以在Mac上直接运行,因此需要判断一下我们的App是跑在了Mac上还是跑在了iPhone上。
因为m1芯片的Mac上只能运行iOS14及以上系统(当然未来说不定有大能会移植低版本iOS系统到Mac上),因此我们只需要判断iOS14之后的系统即可:

var isMac = false
if #available(iOS 14.0, *) {
isMac = ProcessInfo.processInfo.isiOSAppOnMac
}
print(“\(isMac ? “App on Mac” : “App not on Mac”)!”)

当然,还可以直接获取设备型号:

 

#import <sys/utsname.h>
+ (void)deviceModel {
struct utsname systemInfo;
uname(&systemInfo);
NSString *deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
NSLog(@”%@”, deviceModel);
}

“MacBookAir10,1”: “MacBook Air (M1, 2020)”,
“MacBookPro17,1”: “MacBook Pro (13-inch, M1, 2020)”,
“Macmini9,1”: “Mac mini (M1, 2020)”,

iOS逆向—-绕过越狱检测

当然有手动绕过越狱检测的办法,比如自己利用Fishhook或者OC的runtime机制去替换越狱检测的函数,甚至可以使用frida来Hook函数的返回值。这些都是比较稳妥的方法,本篇文章主要介绍的是自动绕过检测的工具xCon。

xCon会在iOS10.3以上系统的设备上导致Cydia崩溃,因此强烈建议先安装Filza后再安装xCon,避免Cydia崩溃后无法移除xCon的尴尬局面
iOS11之后的手机绕过越狱检测看这里
xCon可以从Cydia中安装,是目前为止*强大的越狱检测工具。由n00neimp0rtant与Lunatik共同开发,它据说patch了目前所知的所有越狱检测方法(也有不能patch的应用)。估计是由于影响太大,目前已不开放源码了。

安装方法:
首先在Cydia中添加源http://xcon.crazy.net
然后进入添加的源中选择xCon下载安装,安装完之后需要重启SpringBoard。

安装xCon后,会有两个文件xCon.dylib与xCon.plist出现在设备/Library/MobileSubstrate/DynamicLibraries目录下
进入/Library/MobileSubstrate/DynamicLibraries目录下,查看文件,发现xCon.dylib和xCon.plist

Skys-iPhone:/Library/MobileSubstrate/DynamicLibraries root# ls
MobileSafety.dylib* patcyh.dylib@ xCon.dylib*
MobileSafety.plist patcyh.plist xCon.plist

xCon.plist
该文件为过滤文件,标识在调用com.apple.UIKit时加载xCon.dylib
查看文件内容如下

Skys-iPhone:/Library/MobileSubstrate/DynamicLibraries root# cat xCon.plist
{
Filter = {
Bundles = (com.apple.UIKit);
};
}
Skys-iPhone:/Library/MobileSubstrate/DynamicLibraries root#

 

xCon.dylib
首先我们利用scp命令将文件拷贝到Mac上,然后使用otool工具将该文件的text section反汇编出来从而了解程序的具体逻辑:

➜ ~ scp -P2222 root@127.0.0.1:/Library/MobileSubstrate/DynamicLibraries/xCon.dylib ~/Desktop
root@127.0.0.1’s password:
xCon.dylib 100% 467KB 6.5MB/s 00:00
➜ ~ cd Desktop
➜ Desktop otool -tV xCon.dylib >xContextsection
➜ Desktop

可以根据文件中的函数名,同时结合该工具的原理以及越狱检测的一些常用手段来猜其逻辑,例如越狱检测方法中的文件系统检查,会根据特定的文件路径名来匹配,我们可以使用strings查看文件中的内容,看看会有哪些文件路径名。

➜ Desktop strings xCon.dylib
ipv4
ipv6
Not Found
%s [%s]
CFBundleIdentifier
CFBundleShortVersionString
__TEXT
__text
/System/Library/Lockdown/Services.plist
/var/mobile/Library/Caches/com.apple.mobile.installation.plist
/private/
/dev/
/bin/
/var/mobile/Library/Preferences
com.apple.
v16@?0@”NSString”4@”NSString”8^c12
/etc/fstab
/private/etc/fstab
/var/lib/xcon/fstab
/var/mobile/Applications/
/var/mobile/Containers/Data/Application/
_ptrace
/Applications
/Library/Activator
/Library/Flipswitch
/Library/Ringtones
/Library/Wallpaper
/Library/Switchs
/usr/libexec
/usr/lib/pam
/usr/arm-apple-darwin9
/usr/include
/usr/share
/usr/lib/python2.5
/var/lib/dpkg/info
/var/lib/xcon/paths-deny
……

通过分析,xCon会绕过以下越狱检测方法
(1)根据是否存在特定的越狱文件,及特定文件的权限是否发生变化来判断设备是否越狱
(2)根据沙箱完整性检测设备是否越狱
(3)根据文件系统的分区是否发生变化来检测设备是否越狱
(4)根据是否安装ssh来判断设备是否越狱

iOS逆向—-iOS12之后的静态砸壳

关于静态砸壳其实之前已经介绍过一个工具Clutch,但是由于年久失修,导致其在iOS11之后变得不可用,动不动就kill -9。于是*近又开始研究了一下,发现了一款新的静态砸壳工具flexdecrypt

首先连接到越狱的iPhone上,然后使用wget命令下载*新的deb(wget自行安装):

iPhone:/tmp root# wget https://github.com/JohnCoates/flexdecrypt/releases/download/1.1/flexdecrypt.deb

然后直接安装:

iPhone:/tmp root# dpkg -i flexdecrypt.deb
Selecting previously unselected package flexdecrypt.
(Reading database … 3858 files and directories currently installed.)
Preparing to unpack flexdecrypt.deb …
Unpacking flexdecrypt (1.1) …
Setting up flexdecrypt (1.1) …

安装完之后就可以使用了:

iPhone:/tmp root# flexdecrypt
Error: Missing expected argument ‘<file>’

OVERVIEW: A tool for decrypting apps and Mach-O binaries. Based on the Flex 3
jailbreak app’s source code.

USAGE: flex-decrypt <subcommand>

OPTIONS:
–version Show the version.
-h, –help Show help information.

SUBCOMMANDS:
file (default) Decrypt file.

See ‘flex-decrypt help <subcommand>’ for detailed help.

看描述,flexdecrypt应该不如clutchname智能,因此只能先cd到要砸壳的app目录下,然后再进行砸壳,具体如何找App的路径可以参考之前的博客,这里以砸Quantumult为例:

iPhone:/tmp root# cd /var/containers/Bundle/Application/
iPhone:/var/containers/Bundle/Application/ root# cd 6B8B93D5-DB46-4AAE-A264-F1C93A689B65
iPhone:/var/containers/Bundle/Application/6B8B93D5-DB46-4AAE-A264-F1C93A689B65 root# cd Quantumult.app/
iPhone:/var/containers/Bundle/Application/6B8B93D5-DB46-4AAE-A264-F1C93A689B65/Quantumult.app root# flexdecrypt Quantumult
Wrote decrypted image to /tmp/Quantumult

可以看到静态砸壳的速度是很快的,基本秒出,但是只有一行输出,告诉了你脱壳文件的位置,使用scp命令将文件取出:

➜ ~ scp -P 2222 root@127.0.0.1:”/tmp/Quantumult” ~/Desktop
root@127.0.0.1’s password:
Quantumult 100% 3235KB 34.9MB/s 00:00
➜ ~ cd Desktop
➜ Desktop otool -l Quantumult| grep crypt
cryptoff 16384
cryptsize 2703360
cryptid 0

可以看出已经成功脱壳。

IOS砸壳研究

1.https://github.com/BishopFox/bfdecrypt

Utility to decrypt App Store apps on jailbroken iOS 11.x

2.https://github.com/ivRodriguezCA/decrypt-ios-apps-script

Python script to SSH into your jailbroken device, decrypt an iOS App and transfer it to your local machine
This will decrypt the Instagram app and transfer it from your device to your ~/Desktop:

python ios_ssh.py –lport 2222 -p s3cr37 –app “Instagram”
This will give you an interactive shell to communicate with your device over USB:

python ios_ssh.py –lport 2222 -p s3cr37 -i

The missing guide to debug third party apps on iOS 12
如何调试第三方APP:https://medium.com/@felipejfc/the-ultimate-guide-for-live-debugging-apps-on-jailbroken-ios-12-4c5b48adf2fb

frida的cycript:https://github.com/nowsecure/frida-cycript

iOS应用砸壳

一、砸壳概述及其原理
APP上架会经历 APP->AppStore->源码 加密过程。

应用加密:开发者向AppStore提交应用,都将由苹果官方进行加密处理,以确保用户使用的APP都是经过审核过的,加密后的APP,开发人员无法通过Hopper等反编译应用,也无法使用class-dump。

iOS应用运行原理:应用在磁盘中是加密状态,由于CPU运行不会识别加密文件,因此在启动应用前需要在内核中对加密应用文件进行解密,提取可执行文件才可放入内存中运行。示意图如下:

%title插图%num

逆向需要对加密的二进制文件进行解密才可以做静态分析,解密过程即为砸壳。砸壳有两种:
1、静态砸壳
在已经掌握和了解加密应用的加密算法和逻辑后在不运行加密应用程序的前提下将壳应用程序进行解密处理,静态砸壳方法难度大,并且加密方发现应用被破解后就可能会改用更高级的复杂加密算法。
2、动态砸壳
在运行进程内存中的可执行程序映像入手,将内存中的内容进行转储处理来实现砸壳。该方法相对简单,并且不用关心应用所使用的加密技术。

二、手机越狱
使用爱思助手或pp助手均可以对手机越狱,注意越狱时对应的系统版本号,根据自己系统版本号选择。
越狱后手机上会安装Cydia软件,在软件中选择搜索搜索OpenSSH安装,安装完成后便可以与Mac端通过ssh建立连接。
1、通过工具越狱后会出现h3lix应用:

%title插图%num

2、点击运行h3lix,再点击按钮运行,将会下载安装Cydia应用:

%title插图%num

3、点击Cydia应用查看是否安装OpenSSL,如未安装则搜索安装,如下:

%title插图%num

通过以上1、2、3步骤之后Mac终端就可以和越狱手机进行ssh连接了。命令如下:

ssh root@192.168.1.168 -p 22
1
默认密码:alpine
修改密码执行passwd 输入新密码:yahibo
进入手机中操作与Linux命令相同
注意:手机重启后Cydia应用会失效,需要重新执行第2步重新安装。

三、砸壳工具Clutch使用(动态砸壳)
注意:会遇到砸壳失败,要确定是否在App Store下载,如果不是重新下载。
Clutch需要使用iOS8.0以上的越狱手机应用。
下载链接:https://github.com/KJCracks/Clutch/releases
1、下载后将Clutch-2.0.4放到越狱手机的usr/bin目录下(密码默认为alphine)

scp Clutch-2.0.4 root@192.168.1.168:/usr/bin/
1
2、ssh连接苹果设备,命令如下:

ssh root@192.168.1.168
1
3、进入usr/bin目给Clutch-2.0.4赋予可执行权限:

chmod +x Clutch-2.0.4
1
4、执行Chmod命令查看命令参数:

%title插图%num

Clutch-2.0.4
1

-b 只转储二进制文件
-d 转储应用的.ipa文件即砸壳,砸壳后获取.ipa文件的路径,将.ipa拉到本地即可
-i 获取安装的应用

5、列举安装的应用:

Clutch-2.0.4 -i
1%title插图%num

6、开始砸壳,选择编号2对微信进行砸壳:

Clutch-2.0.4 -d 2
1
运行如下:

%title插图%num

*后生成一个砸壳后的包路径:
/private/var/mobile/Documents/Dumped/com.tencent.xin-iOS9.0-(Clutch-2.0.4).ipa
将Dumped文件下载到Mac中:

scp -r root@192.168.1.168:/private/var/mobile/Documents/Dumped ipas/
1
7、将获取到的.ipa修改为wxtest.zip并解压,进入wxtest文件中的Payload中,执行命令:

class-dump -H WeChat.app -o apph
1
结束后apph中为微信对应的所有头文件信息。如图:

apph中为微信对应的所有头文件信息。如图:

%title插图%num

Interpolator的用法

Interpolator的用法

Interpolator这个东西很难进行翻译,直译过来的话是补间器的意思,它的主要作用是可以控制动画的变化速率,比如去实现一种非线性运动的动画效果。那么什么叫做非线性运动的动画效果呢?就是说动画改变的速率不是一成不变的,像加速运动以及减速运动都属于非线性运动。

 

不过Interpolator并不是属性动画中新增的技术,实际上从Android 1.0版本开始就一直存在Interpolator接口了,而之前的补间动画当然也是支持这个功能的。只不过在属性动画中新增了一个TimeInterpolator接口,这个接口是用于兼容之前的Interpolator的,这使得所有过去的Interpolator实现类都可以直接拿过来放到属性动画当中使用,那么我们来看一下现在TimeInterpolator接口的所有实现类,如下图所示:

 

%title插图%num

 

可以看到,TimeInterpolator接口已经有非常多的实现类了,这些都是Android系统内置好的并且我们可以直接使用的Interpolator。每个Interpolator都有它各自的实现效果,比如说AccelerateInterpolator就是一个加速运动的Interpolator,而DecelerateInterpolator就是一个减速运动的Interpolator。

 

我觉得细心的朋友应该早已经发现了,在前面两篇文章当中我们所学到的所有属性动画,其实都不是在进行一种线程运动。比如说在“上”篇文章中使用ValueAnimator所打印的值如下所示:

 

%title插图%num

 

可以看到,一开始的值变化速度明显比较慢,仅0.0开头的就打印了4次,之后开始加速,*后阶段又开始减速,因此我们可以很明显地看出这一个先加速后减速的Interpolator。

 

那么再来看一下在“中”篇文章中完成的小球移动加变色的功能,如下图所示:

 

%title插图%num

从上图中我们明显可以看出,小球一开始运动速度比较慢,然后逐渐加速,中间的部分运动速度就比较快,接下来开始减速,*后缓缓停住。另外颜色变化也是这种规律,一开始颜色变化的比较慢,中间颜色变化的很快,*后阶段颜色变化的又比较慢。

 

从以上几点我们就可以总结出一个结论了,使用属性动画时,系统默认的Interpolator其实就是一个先加速后减速的Interpolator,对应的实现类就是AccelerateDecelerateInterpolator。

 

当然,我们也可以很轻松地修改这一默认属性,将它替换成任意一个系统内置好的Interpolator。就拿“中”篇文章中的代码来举例吧,MyAnimView中的startAnimation()方法是开启动画效果的入口,这里我们对Point对象的坐标稍做一下修改,让它变成一种垂直掉落的效果,代码如下所示:

  1. private void startAnimation() {  
  2.     Point startPoint = new Point(getWidth() / 2, RADIUS);  
  3.     Point endPoint = new Point(getWidth() / 2, getHeight() – RADIUS);  
  4.     ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);  
  5.     anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
  6.         @Override  
  7.         public void onAnimationUpdate(ValueAnimator animation) {  
  8.             currentPoint = (Point) animation.getAnimatedValue();
  9.             invalidate();
  10.         }
  11.     });
  12.     anim.setDuration(2000);  
  13.     anim.start();
  14. }

这里主要是对Point构造函数中的坐标值进行了一下改动,那么现在小球运动的动画效果应该是从屏幕正中央的顶部掉落到底部。但是现在默认情况下小球的下降速度肯定是先加速后减速的,这不符合物理的常识规律,如果把小球视为一个自由落体的话,那么下降的速度应该是越来越快的。我们怎样才能改变这一默认行为呢?其实很简单,调用Animator的setInterpolator()方法就可以了,这个方法要求传入一个实现TimeInterpolator接口的实例,那么比如说我们想要实现小球下降越来越快的效果,就可以使用AccelerateInterpolator,代码如下所示:

  1. private void startAnimation() {  
  2.     Point startPoint = new Point(getWidth() / 2, RADIUS);  
  3.     Point endPoint = new Point(getWidth() / 2, getHeight() – RADIUS);  
  4.     ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);  
  5.     anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
  6.         @Override  
  7.         public void onAnimationUpdate(ValueAnimator animation) {  
  8.             currentPoint = (Point) animation.getAnimatedValue();
  9.             invalidate();
  10.         }
  11.     });
  12.     anim.setInterpolator(new AccelerateInterpolator(2f));  
  13.     anim.setDuration(2500);  
  14.     anim.start();
  15. }

代码很简单,这里调用了setInterpolator()方法,然后传入了一个AccelerateInterpolator的实例,注意AccelerateInterpolator的构建函数可以接收一个float类型的参数,这个参数是用于控制加速度的。现在运行一下代码,效果如下图所示:

 

%title插图%num

 

OK,效果非常明显,说明我们已经成功替换掉了默认的Interpolator,AccelerateInterpolator确实是生效了。但是现在的动画效果看上去仍然是怪怪的,因为一个小球从很高的地方掉落到地面上直接就静止了,这也是不符合物理规律的,小球撞击到地面之后应该要反弹起来,然后再次落下,接着再反弹起来,又再次落下,以此反复,*后静止。这个功能我们当然可以自己去写,只不过比较复杂,所幸的是,Android系统中已经提供好了这样一种Interpolator,我们只需要简单地替换一下就可以完成上面的描述的效果,代码如下所示:

  1. private void startAnimation() {  
  2.     Point startPoint = new Point(getWidth() / 2, RADIUS);  
  3.     Point endPoint = new Point(getWidth() / 2, getHeight() – RADIUS);  
  4.     ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);  
  5.     anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
  6.         @Override  
  7.         public void onAnimationUpdate(ValueAnimator animation) {  
  8.             currentPoint = (Point) animation.getAnimatedValue();
  9.             invalidate();
  10.         }
  11.     });
  12.     anim.setInterpolator(new BounceInterpolator());  
  13.     anim.setDuration(3000);  
  14.     anim.start();
  15. }

可以看到,我们只是将设置的Interpolator换成了BounceInterpolator的实例,而BounceInterpolator就是一种可以模拟物理规律,实现反复弹起效果的Interpolator。另外还将整体的动画时间稍微延长了一点,因为小球反复弹起需要比之前更长的时间。现在重新运行一下代码,效果如下图所示:

 

%title插图%num

 

OK!效果还是非常不错的。那么这里我们只是选了几个系统实现好的Interpolator,由于内置Interpolator非常多,就不一一进行讲解了,大家可以自己去使用一下其它的几种Interpolator来看一看效果。

 

但是,只会用一下系统提供好的Interpolator,我们显然对自己的要求就太低了,既然是学习属性动画的高级用法,那么自然要将它研究透了。下面我们就来看一下Interpolator的内部实现机制是什么样的,并且来尝试写一个自定义的Interpolator。

 

首先看一下TimeInterpolator的接口定义,代码如下所示:

  1. /** 
  2.  * A time interpolator defines the rate of change of an animation. This allows animations 
  3.  * to have non-linear motion, such as acceleration and deceleration. 
  4.  */  
  5. public interface TimeInterpolator {  
  6.     /** 
  7.      * Maps a value representing the elapsed fraction of an animation to a value that represents 
  8.      * the interpolated fraction. This interpolated value is then multiplied by the change in 
  9.      * value of an animation to derive the animated value at the current elapsed animation time. 
  10.      * 
  11.      * @param input A value between 0 and 1.0 indicating our current point 
  12.      *        in the animation where 0 represents the start and 1.0 represents 
  13.      *        the end 
  14.      * @return The interpolation value. This value can be more than 1.0 for 
  15.      *         interpolators which overshoot their targets, or less than 0 for 
  16.      *         interpolators that undershoot their targets. 
  17.      */  
  18.     float getInterpolation(float input);  
  19. }

OK,接口还是非常简单的,只有一个getInterpolation()方法。大家有兴趣可以通过注释来对这个接口进行详解的了解,这里我就简单解释一下,getInterpolation()方法中接收一个input参数,这个参数的值会随着动画的运行而不断变化,不过它的变化是非常有规律的,就是根据设定的动画时长匀速增加,变化范围是0到1。也就是说当动画一开始的时候input的值是0,到动画结束的时候input的值是1,而中间的值则是随着动画运行的时长在0到1之间变化的。

 

说到这个input的值,我觉得有不少朋友可能会联想到我们在“中”篇文章中使用过的fraction值。那么这里的input和fraction有什么关系或者区别呢?答案很简单,input的值决定了fraction的值。input的值是由系统经过计算后传入到getInterpolation()方法中的,然后我们可以自己实现getInterpolation()方法中的算法,根据input的值来计算出一个返回值,而这个返回值就是fraction了。

 

因此,*简单的情况就是input值和fraction值是相同的,这种情况由于input值是匀速增加的,因而fraction的值也是匀速增加的,所以动画的运动情况也是匀速的。系统中内置的LinearInterpolator就是一种匀速运动的Interpolator,那么我们来看一下它的源码是怎么实现的:

  1. /** 
  2.  * An interpolator where the rate of change is constant 
  3.  */  
  4. @HasNativeInterpolator  
  5. public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {  
  6.     public LinearInterpolator() {  
  7.     }
  8.     public LinearInterpolator(Context context, AttributeSet attrs) {  
  9.     }
  10.     public float getInterpolation(float input) {  
  11.         return input;  
  12.     }
  13.     /** @hide */  
  14.     @Override  
  15.     public long createNativeInterpolator() {  
  16.         return NativeInterpolatorFactoryHelper.createLinearInterpolator();  
  17.     }
  18. }

这里我们只看getInterpolation()方法,这个方法没有任何逻辑,就是把参数中传递的input值直接返回了,因此fraction的值就是等于input的值的,这就是匀速运动的Interpolator的实现方式。

 

当然这是*简单的一种Interpolator的实现了,我们再来看一个稍微复杂一点的。既然现在大家都知道了系统在默认情况下使用的是AccelerateDecelerateInterpolator,那我们就来看一下它的源码吧,如下所示:

  1. /** 
  2.  * An interpolator where the rate of change starts and ends slowly but 
  3.  * accelerates through the middle. 
  4.  *  
  5.  */  
  6. @HasNativeInterpolator  
  7. public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {  
  8.     public AccelerateDecelerateInterpolator() {  
  9.     }
  10.     @SuppressWarnings({“UnusedDeclaration”})  
  11.     public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {  
  12.     }
  13.     public float getInterpolation(float input) {  
  14.         return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;  
  15.     }
  16.     /** @hide */  
  17.     @Override  
  18.     public long createNativeInterpolator() {  
  19.         return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();  
  20.     }
  21. }

代码虽然没有变长很多,但是getInterpolation()方法中的逻辑已经明显变复杂了,不再是简单地将参数中的input进行返回,而是进行了一个较为复杂的数学运算。那这里我们来分析一下它的算法实现,可以看到,算法中主要使用了余弦函数,由于input的取值范围是0到1,那么cos函数中的取值范围就是π到2π。而cos(π)的结果是-1,cos(2π)的结果是1,那么这个值再除以2加上0.5之后,getInterpolation()方法*终返回的结果值还是在0到1之间。只不过经过了余弦运算之后,*终的结果不再是匀速增加的了,而是经历了一个先加速后减速的过程。我们可以将这个算法的执行情况通过曲线图的方式绘制出来,结果如下图所示:

 

%title插图%num

 

可以看到,这是一个S型的曲线图,当横坐标从0变化到0.2的时候,纵坐标的变化幅度很小,但是之后就开始明显加速,*后横坐标从0.8变化到1的时候,纵坐标的变化幅度又变得很小。

 

OK,通过分析LinearInterpolator和AccelerateDecelerateInterpolator的源码,我们已经对Interpolator的内部实现机制有了比较清楚的认识了,那么接下来我们就开始尝试编写一个自定义的Interpolator。

 

编写自定义Interpolator*主要的难度都是在于数学计算方面的,由于我数学并不是很好,因此这里也就写一个简单点的Interpolator来给大家演示一下。既然属性动画默认的Interpolator是先加速后减速的一种方式,这里我们就对它进行一个简单的修改,让它变成先减速后加速的方式。新建DecelerateAccelerateInterpolator类,让它实现TimeInterpolator接口,代码如下所示:

  1. public class DecelerateAccelerateInterpolator implements TimeInterpolator{  
  2.     @Override  
  3.     public float getInterpolation(float input) {  
  4.         float result;  
  5.         if (input <= 0.5) {  
  6.             result = (float) (Math.sin(Math.PI * input)) / 2;  
  7.         } else {  
  8.             result = (float) (2 – Math.sin(Math.PI * input)) / 2;  
  9.         }
  10.         return result;  
  11.     }
  12. }

这段代码是使用正弦函数来实现先减速后加速的功能的,因为正弦函数初始弧度的变化值非常大,刚好和余弦函数是相反的,而随着弧度的增加,正弦函数的变化值也会逐渐变小,这样也就实现了减速的效果。当弧度大于π/2之后,整个过程相反了过来,现在正弦函数的弧度变化值非常小,渐渐随着弧度继续增加,变化值越来越大,弧度到π时结束,这样从0过度到π,也就实现了先减速后加速的效果。

 

同样我们可以将这个算法的执行情况通过曲线图的方式绘制出来,结果如下图所示:

 

%title插图%num

 

可以看到,这也是一个S型的曲线图,只不过曲线的方向和刚才是相反的。从上图中我们可以很清楚地看出来,一开始纵坐标的变化幅度很大,然后逐渐变小,横坐标到0.5的时候纵坐标变化幅度趋近于零,之后随着横坐标继续增加纵坐标的变化幅度又开始变大,的确是先减速后加速的效果。

 

那么现在我们将DecelerateAccelerateInterpolator在代码中进行替换,如下所示:

  1. private void startAnimation() {  
  2.     Point startPoint = new Point(getWidth() / 2, RADIUS);  
  3.     Point endPoint = new Point(getWidth() / 2, getHeight() – RADIUS);  
  4.     ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);  
  5.     anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
  6.         @Override  
  7.         public void onAnimationUpdate(ValueAnimator animation) {  
  8.             currentPoint = (Point) animation.getAnimatedValue();
  9.             invalidate();
  10.         }
  11.     });
  12.     anim.setInterpolator(new DecelerateAccelerateInterpolator());  
  13.     anim.setDuration(3000);  
  14.     anim.start();
  15. }

非常简单,就是将DecelerateAccelerateInterpolator的实例传入到setInterpolator()方法当中。重新运行一下代码,效果如下图所示:

 

%title插图%num

 

OK!小球的运动确实是先减速后加速的效果,说明我们自定义的Interpolator已经可以正常工作了。通过这样一个程度的学习,相信大家对属性动画Interpolator的理解和使用都达到了一个比较深刻的层次了。

 

ViewPropertyAnimator的用法

ViewPropertyAnimator其实算不上什么高级技巧,它的用法格外的简单,只不过和前面所学的所有属性动画的知识不同,它并不是在3.0系统当中引入的,而是在3.1系统当中附增的一个新的功能,因此这里我们把它作为整个属性动画系列的收尾部分。

 

我们都知道,属性动画的机制已经不是再针对于View而进行设计的了,而是一种不断地对值进行操作的机制,它可以将值赋值到指定对象的指定属性上。但是,在*大多数情况下,我相信大家主要都还是对View进行动画操作的。Android开发团队也是意识到了这一点,没有为View的动画操作提供一种更加便捷的用法确实是有点太不人性化了,于是在Android 3.1系统当中补充了ViewPropertyAnimator这个机制。

 

那我们先来回顾一下之前的用法吧,比如我们想要让一个TextView从常规状态变成透明状态,就可以这样写:

  1. ObjectAnimator animator = ObjectAnimator.ofFloat(textview, “alpha”, 0f);  
  2. animator.start();

看上去复杂吗?好像也不怎么复杂,但确实也不怎么容易理解。我们要将操作的view、属性、变化的值都一起传入到ObjectAnimator.ofFloat()方法当中,虽然看上去也没写几行代码,但这不太像是我们平时使用的面向对象的思维。

 

那么下面我们就来看一下如何使用ViewPropertyAnimator来实现同样的效果,ViewPropertyAnimator提供了更加易懂、更加面向对象的API,如下所示:

  1. textview.animate().alpha(0f);

果然非常简单!不过textview.animate()这个方法是怎么回事呢?animate()方法就是在Android 3.1系统上新增的一个方法,这个方法的返回值是一个ViewPropertyAnimator对象,也就是说拿到这个对象之后我们就可以调用它的各种方法来实现动画效果了,这里我们调用了alpha()方法并转入0,表示将当前的textview变成透明状态。

 

怎么样?比起使用ObjectAnimator,ViewPropertyAnimator的用法明显更加简单易懂吧。除此之外,ViewPropertyAnimator还可以很轻松地将多个动画组合到一起,比如我们想要让textview运动到500,500这个坐标点上,就可以这样写:

  1. textview.animate().x(500).y(500);  

可以看出,ViewPropertyAnimator是支持连缀用法的,我们想让textview移动到横坐标500这个位置上时调用了x(500)这个方法,然后让textview移动到纵坐标500这个位置上时调用了y(500)这个方法,将所有想要组合的动画通过这种连缀的方式拼接起来,这样全部动画就都会一起被执行。

 

那么怎样去设定动画的运行时长呢?很简单,也是通过连缀的方式设定即可,比如我们想要让动画运行5秒钟,就可以这样写:

  1. textview.animate().x(500).y(500).setDuration(5000);  

除此之外,本篇文章*部分所学的Interpolator技术我们也可以应用在ViewPropertyAnimator上面,如下所示:

  1. textview.animate().x(500).y(500).setDuration(5000)  
  2.         .setInterpolator(new BounceInterpolator());  

用法很简单,同样也是使用连缀的方式。相信大家现在都已经体验出来了,ViewPropertyAnimator其实并没有什么太多的技巧可言,用法基本都是大同小异的,需要用到什么功能就连缀一下,因此更多的用法大家只需要去查阅一下文档,看看还支持哪些功能,有哪些接口可以调用就可以了。

 

那么除了用法之外,关于ViewPropertyAnimator有几个细节还是值得大家注意一下的:

 

  • 整个ViewPropertyAnimator的功能都是建立在View类新增的animate()方法之上的,这个方法会创建并返回一个ViewPropertyAnimator的实例,之后的调用的所有方法,设置的所有属性都是通过这个实例完成的。
  • 大家注意到,在使用ViewPropertyAnimator时,我们自始至终没有调用过start()方法,这是因为新的接口中使用了隐式启动动画的功能,只要我们将动画定义完成之后,动画就会自动启动。并且这个机制对于组合动画也同样有效,只要我们不断地连缀新的方法,那么动画就不会立刻执行,等到所有在ViewPropertyAnimator上设置的方法都执行完毕后,动画就会自动启动。当然如果不想使用这一默认机制的话,我们也可以显式地调用start()方法来启动动画。
  • ViewPropertyAnimator的所有接口都是使用连缀的语法来设计的,每个方法的返回值都是它自身的实例,因此调用完一个方法之后可以直接连缀调用它的另一个方法,这样把所有的功能都串接起来,我们甚至可以仅通过一行代码就完成任意复杂度的动画功能。

 

好的,那么到这里为止,整个Android属性动画完全解析的系列就全部结束了,感谢大家有耐心看到*后。

ViewStub用法

ViewStub用法

在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么*通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源。虽然把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。

推荐的做法是使用android.view.ViewStub,ViewStub 是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有 ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向 的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还 是不要显示某个布局。

但ViewStub也不是万能的,下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制。

首先来说说ViewStub的一些特点:

1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。

2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。

基于以上的特点,那么可以考虑使用ViewStub的情况有:

1. 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。

因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和 隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。

2. 想要控制显示与隐藏的是一个布局文件,而非某个View。

因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。

所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。

下面来看一个实例

在这个例子中,要显示二种不同的布局,一个是用TextView显示一段文字,另一个则是用ImageView显示一个图片。这二个是在onCreate()时决定是显示哪一个,这里就是应用ViewStub的*佳地点。

先来看看布局,一个是主布局,里面只定义二个ViewStub,一个用来控制TextView一个用来控制ImageView,另外就是一个是为显示文字的做的TextView布局,一个是为ImageView而做的布局:

 

复制代码
    <?xml version="1.0" encoding="utf-8"?>  
    <LinearLayout  
      xmlns:android="http://schemas.android.com/apk/res/android"  
      android:orientation="vertical"  
      android:layout_width="fill_parent"  
      android:layout_height="fill_parent"  
      android:gravity="center_horizontal">  
      <ViewStub   
        android:id="@+id/viewstub_demo_text"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_marginLeft="5dip"  
        android:layout_marginRight="5dip"  
        android:layout_marginTop="10dip"  
        android:layout="@layout/viewstub_demo_text_layout"/>  
      <ViewStub   
        android:id="@+id/viewstub_demo_image"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_marginLeft="5dip"  
        android:layout_marginRight="5dip"  
        android:layout="@layout/viewstub_demo_image_layout"/>  
    </LinearLayout>
复制代码

 

为TextView的布局:

 

复制代码
    <?xml version="1.0" encoding="utf-8"?>  
    <LinearLayout  
      xmlns:android="http://schemas.android.com/apk/res/android"  
      android:orientation="vertical"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content">  
        <TextView  
            android:id="@+id/viewstub_demo_textview"  
            android:layout_width="fill_parent"  
            android:layout_height="wrap_content"  
            android:background="#aa664411"  
            android:textSize="16sp"/>  
    </LinearLayout>
复制代码

 

为ImageView的布局:

 

复制代码
    <?xml version="1.0" encoding="utf-8"?>  
    <LinearLayout  
      xmlns:android="http://schemas.android.com/apk/res/android"  
      android:orientation="vertical"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content">  
        <ImageView  
            android:id="@+id/viewstub_demo_imageview"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"/>  
    </LinearLayout>
复制代码

 

下面来看代码,决定来显示哪一个,只需要找到相应的ViewStub然后调用其infalte()就可以获得相应想要的布局:

 

复制代码
    package com.effective;  
      
    import android.app.Activity;  
    import android.os.Bundle;  
    import android.view.ViewStub;  
    import android.widget.ImageView;  
    import android.widget.TextView;  
      
    public class ViewStubDemoActivity extends Activity {  
        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.viewstub_demo_activity);  
            if ((((int) (Math.random() * 100)) & 0x01) == 0) {  
                // to show text  
                // all you have to do is inflate the ViewStub for textview  
                ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text);  
                stub.inflate();  
                TextView text = (TextView) findViewById(R.id.viewstub_demo_textview);  
                text.setText("The tree of liberty must be refreshed from time to time" +  
                        " with the blood of patroits and tyrants! Freedom is nothing but " +  
                        "a chance to be better!");  
            } else {  
                // to show image  
                // all you have to do is inflate the ViewStub for imageview  
                ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image);  
                stub.inflate(); 
                ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview);  
                image.setImageResource(R.drawable.happy_running_dog);  
            }  
        }  
    }
复制代码

 

运行结果:

%title插图%num%title插图%num

使用的时候的注意事项:

1. 某些布局属性要加在ViewStub而不是实际的布局上面,才会起作用,比如上面用的android:layout_margin*系列属性,如果加在 TextView上面,则不会起作用,需要放在它的ViewStub上面才会起作用。而ViewStub的属性在inflate()后会都传给相应的布 局。

 

1.ViewStub之所以常称之为“延迟化加载”,是因为在教多数情况下,程序 无需显示ViewStub所指向的布局文件,只有在特定的某些较少条件下,此时ViewStub所指向的布局文件才需要被inflate,且此布局文件直 接将当前ViewStub替换掉,具体是通过viewStub.infalte()或 viewStub.setVisibility(View.VISIBLE)来完成;

2.正确把握住ViewStub的应用场景非常重要,正如如1中所描述需求场景下,使用ViewStub可以优化布局;

3.对ViewStub的inflate操作只能进行一次,因为inflate的 时候是将其指向的布局文件解析inflate并替换掉当前ViewStub本身(由此体现出了ViewStub“占位符”性质),一旦替换后,此时原来的 布局文件中就没有ViewStub控件了,因此,如果多次对ViewStub进行infalte,会出现错误信息:ViewStub must have a non-null ViewGroup viewParent。

4.3中所讲到的ViewStub指向的布局文件解析inflate并替换掉当前 ViewStub本身,并不是完全意义上的替换(与include标签还不太一样),替换时,布局文件的layout params是以ViewStub为准,其他布局属性是以布局文件自身为准。

5.ViewStub本身是不可见的,对 ViewStub setVisibility(..)与其他控件不一样,ViewStub的setVisibility 成View.VISIBLE或INVISIBLE如果是首次使用,都会自动inflate其指向的布局文件,并替换ViewStub本身,再次使用则是相 当于对其指向的布局文件设置可见性。

 

 

viewStub中加载layout的代码是

  1. public View inflate() {
  2.     final ViewParent viewParent = getParent();// 获取当前view的父view,用于获取需要加载的layout的index  
  3.     if (viewParent != null && viewParent instanceof ViewGroup) {
  4.         if (mLayoutResource != 0) {
  5.             final ViewGroup parent = (ViewGroup) viewParent;  
  6.             final LayoutInflater factory;
  7.             if (mInflater != null) {
  8.                 factory = mInflater;  
  9.             } else {
  10.                 factory = LayoutInflater.from(mContext);  
  11.             }
  12.             final View view = factory.<strong><span style=”font-size:14px;color:#ff0000;”>inflate</span></strong>(mLayoutResource, parent, false);// 获取需要加载的layout  
  13.             if (mInflatedId != NO_ID) {
  14.                 view.setId(mInflatedId);
  15.             }
  16.             final int index = parent.indexOfChild(this);  
  17.             parent.removeViewInLayout(this);// 删除之前加载的view
  18.             final ViewGroup.LayoutParams layoutParams = getLayoutParams();  
  19.             if (layoutParams != null) {
  20.                 parent.addView(view, index, layoutParams);
  21.             } else {
  22.                 parent.<strong><span style=“font-size:14px;color:#ff0000;”>addView</span></strong>(view, index);// 添加view  
  23.             }
  24.             mInflatedViewRef = new WeakReference<View>(view);  
  25.             if (mInflateListener != null) {
  26.                 mInflateListener.onInflate(this, view);
  27.             }
  28.             return view;
  29.         } else {
  30.             throw new IllegalArgumentException(“ViewStub must have a valid layoutResource”);
  31.         }
  32.     } else {
  33.         throw new IllegalStateException(“ViewStub must have a non-null ViewGroup viewParent”);
  34.     }
  35. }

 

Volley(一 )—— 框架简介

Volley(一 )—— 框架简介

一、引言

虽然网上已经有很多大神、高手都写过了类似的帖子,但作为新人,必须要走模仿的道路,再考虑超越,因此学习大神的笔记,记录自己的理解,是一个菜鸟走向成功的必经之路啊。如签名所言,记录自己摸爬滚打的经历,享受不悔的青春。废话不多说,言归正传。

二、Volley是什么?

Volley是 Google 推出的 Android 异步网络请求框架和图片加载框架。

三、Volley的主要特性

(1). 提供对网络请求自动调控的管理功能RequestQueue请求队列
(2).提供对网络请求进行缓存的功能,数据可以二级缓存,图片可以三级缓存,缓存有效时间默认使用请求响应头内CacheControl设置的缓存有效时间,也就是缓存有效时间由服务端动态确定
(3). 提供强大的请求取消功能
(4). 提供简便的图片加载工具ImageLoader&NetworkImageView

(5).提供强大的自定制功能,可以自己按照自己的实际需求定制request<T>子类

四、volley的总体设计图

%title插图%num

上图源自网络。如上图所示,volley主要是通过两种Diapatch Thread不断从RequestQueue中取出请求,根据是否已缓存调用Cache或Network这两类数据获取接口之一,从内存缓存或是服务器取 得请求的数据,然后交由ResponseDelivery去做结果分发及回调处理。

五、volley中的一些概念

  • Volley:Volley 对外暴露的 API,通过 newRequestQueue(…) 函数新建并启动一个请求队列RequestQueue。
  • Request:表示一个请求的抽象类。StringRequest、JsonRequest、ImageRequest都是它的子类,表示某种类型的请求。
  • RequestQueue:表示请求队列,里面包含一个CacheDispatcher(用于处理走缓存请求的调度线程)、 NetworkDispatcher数组(用于处理走网络请求的调度线程),一个ResponseDelivery(返回结果分发接口),通过 start() 函数启动时会启动CacheDispatcher和NetworkDispatchers。
  • CacheDispatcher:一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求 处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入 NetworkDispatcher去调度处理。
  • NetworkDispatcher:一个线程,用于调度处理走网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。
  • ResponseDelivery:返回结果分发接口,目前只有基于ExecutorDelivery的在入参 handler 对应线程内进行分发。
  • HttpStack:处理 Http 请求,返回请求结果。目前 Volley 中有基于 HttpURLConnection 的HurlStack和 基于 Apache HttpClient 的HttpClientStack。
  • Network:调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。
  • Cache:缓存请求结果,Volley 默认使用的是基于 sdcard 的DiskBasedCache。NetworkDispatcher得到请求结果后判断是否需要存储在 Cache,CacheDispatcher会从 Cache 中取缓存结果。

六、volley请求处理流程图

%title插图%num

上图源自网络。

Android应用开发 WebView与服务器端的Js交互

Android应用开发 WebView与服务器端的Js交互

*近公司再添加功能的时候,有一部分功能是用的html,在一个浏览器或webview中展示出html即可。当然在这里我们当然用webview控件喽

 

WebApp的好处:

在应用里嵌套web的好处有这么几点,1,跨平台,不仅可以在Android上运行,也可以在iOS上运行,而且样式什么的*对统一,因为都是加载的html,用的都是同一套html

2,修改灵活,容易更新版本。例如大家常看到的app里面的广告页,大多是嵌套的html,这样只要后台替换一下页面的内容,手机端就会改变展现内容,跟新版本也是如此,因为界面什么得成了在服务器端,所以要是想跟新界面什么得,只需要在后台修改在发布即可,不需要用户再重新下载app。这个好处我觉得对ios是有很大帮助的,哈哈,绕开苹果审核嘛,由于html我们可以随意替换,审核时可以把违规的部分隐藏,上线之后就可以随意改了,哈哈,你们懂得。

 

当然,开发webapp当然也有局限,就是网速什么的,这个咱无法改变,这里也不废话。不过在开发中呢,如果只是页面之间的交互的话,我们只需提供一个webview控件即可,

可是要是涉及到和手机设备或软件交互的话(如打开相册,摄像头等等),这就需要我们和页面经行js交互,js交互可以说是双向的,一种是,我们调用页面的,就是调用服务端的js方法,另一个呢则是服务端调用我们Android里面的代码,调用其实很简单,下面说一下怎样调用。

当然我们先等有一个WebView,先创建一个Activity,然后设置布局,穿件WebView,布局和Activity如下:

activity_webview.xml



[html] view plain copy print?在CODE上查看代码片派生到我的代码片
01.<?xml version="1.0" encoding="utf-8"?>  
02.<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
03.    android:layout_width="match_parent"  
04.    android:layout_height="match_parent"  
05.    android:orientation="vertical" >  
06.    <WebView   
07.        android:id="@+id/webview"  
08.        android:layout_width="match_parent"  
09.        android:layout_height="match_parent"  
10.        />  
11.  
12.</LinearLayout>  




然后是activity,

WebViewActivity.activity



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.import android.app.Activity;  
02.import android.os.Bundle;  
03.import android.webkit.WebSettings;  
04.import android.webkit.WebView;  
05.  
06.public class WebViewActivity extends Activity {  
07.    private static final String url = "http://192.168.30.199:8080/song/test.html";  
08.    private WebView mWebView;  
09.    @Override  
10.    protected void onCreate(Bundle savedInstanceState) {  
11.        super.onCreate(savedInstanceState);  
12.        setContentView(R.layout.activity_webviw);  
13.        initView();  
14.    }  
15.  
16.    private void initView() {  
17.        mWebView = (WebView) findViewById(R.id.webview);  
18.        //或的WebView的Setting  
19.        WebSettings settings = mWebView.getSettings();  
20.        //设置支持js,看方法名字就知道啥意思  
21.        settings.setJavaScriptEnabled(true);  
22.        //加载网页路径  
23.        mWebView.loadUrl(url);  
24.    }  
25.}  




上面就是一个简单的webview,然后很常规的设置属性,然后再加载要加载的页面路径,这样一般就可在网页里面自由点击跳转了,但是要和手机交互的话需要我们写js交互的代码了。

首先说怎样调用服务器端的js方法,很简单,和加载网页路径基本上一样如下:



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.mWebView.loadUrl("javascript:forSmallPhoto()");  




就这么简单的一句话你就可以调用服务器端的js方法了,其中JavaScript:是固定写法forSmallPhoto()则是服务端的js方法名字,这是一个无参数的方法,当然也可以传参,这需要我们拼凑字符串,mWebView.loadUrl("javascript:forSmallPhoto('" + data + "')");其中data就是一个变量,也就是你要传的参数值,当然也可以支持多参数传送,这得看你服务器端的js方法有几个参数了,其实就是我们调用一个方法一样,只不过这个方法是在服务器端的。我们调用服务器js,是为了,当Android完成某些功能后,需要告诉服务器,则我们可以调用js来告诉他我们完成了。

 

在一种就是,服务端调用我们的Android代码了,这里Android中也是封装好了接口

我们可以通过void android.webkit.WebView.addJavascriptInterface(Object object, String name)的方法来实现服务器端调用我们的代码,其中这个方法有两个参数,一个是object,另一个是String类型的; 只要webview调用了这个方法就可以调用我们的代码了。而要调用的代码我们写在Object里面,首先我们就先实现这个Object,我们创建一个类,JavaScriptInterface。Android中APi Guides中提供的Demo中取得累的名字是JavaScriptInterface,那我们也用这个名字把。然后实现它,然后随便在里面写一个方法,如下面

JavaScriptInterface.Java类



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.import java.util.HashMap;  
02.import java.util.Map;  
03.  
04.import android.content.Context;  
05.import android.os.Handler;  
06.import android.os.Message;  
07.import android.text.TextUtils;  
08.import android.util.Log;  
09.import android.webkit.JavascriptInterface;  
10.import android.widget.Toast;  
11.  
12./** 
13. *  
14. * Title: JavaScriptInterface.java Description: 
15. *  
16. * @author Liusong 
17. * @version V1.0 
18. */  
19.public class JavaScriptInterface {    
20.          
21.    /** Instantiate the interface and set the context */  
22.    public JavaScriptInterface() {  
23.    }  
24.  
25.    /** Show a toast from the web page */  
26.    @JavascriptInterface  
27.    public void showToast() {  
28.        Log.i("TAG", "调用成功==================》》》》》");  
29.  
30.    }  
31.  
32.}  





这样就完成了一个简单的JavaScriptInterface类,这个类的方法是自己随便写的,其中,先说一下这里要注意的几点,首先重要的@JavascriptInterface这个注解,你会发现去掉也不会报错,但是这个是很早重要的,如果你想让服务器端调用你的方法,你就要加上这个注解@JavascriptInterface。在4.4api中说道,一定要加这个注解,负责调用不会成功,其实我在开发中,用红米1s,4.3的系统,就没法调用成功了,当时还纳闷,因为当时手里的文档是4.2的,很是郁闷。所以在这里强掉,一定要在自己写的方法前面加上@JavascriptInterface。

还有一个注意的是方法的参数,这里是一个无参方法,当然这里你也可以写一个有参方法,这里先提一下,待会会配合html里面的js说道,我们先说void android.webkit.WebView.addJavascriptInterface(Object object, String name)这个方法里面的第二个参数,第二个参数你可以理解为是标识符,就是服务器端调用你方法时,需要找到你,怎么找到?就是通过这个标识符,标识符是自己随便定的,但是,你要告诉后台开发人员你的标识符是什么,我们这里把这第二个参数设置为“Android”。下面我给出我测试的html代码结合着看你就明白了。

test.html



[html] view plain copy print?在CODE上查看代码片派生到我的代码片
01.<!doctype html>  
02.<html>  
03.<head>  
04.    <meta name="viewport" content="width=device-width, initial-scale=1" charset="GBK">  
05.    <title>测试</title>  
06.</head>  
07.  
08.<body>  
09.  
10.<div data-role="page" >  
11.      
12.<script type="text/javascript">  
13.     function callAndroidAction(action) {  
14.        Android.showToast();        alert("我敢保证,你现在用的是演示一");  
15.    }  
16.     function forSmallPhoto(action) {  
17.        alert("我敢保证,你现在用的是演示一"+action);  
18.    }  
19.</script>  
20.  
21.    <div data-role="header">  
22.        <h1>调用图库</h1>  
23.        <!--   <a href="#" class="ui-btn">返回</a>-->  
24.    </div>  
25.  
26.    <div data-role="main" class="ui-content">  
27.  
28.        <div style="width: 98%;margin: 0 auto; text-align: center">  
29.            <a href="#" class=" ui-btn ui-btn-inline" onclick="callAndroidAction(0)">调用图库  </a>  
30.              
31.            <a href="#" class=" ui-btn ui-btn-inline" onclick="callAndroidAction('2')"> 充值  </a>  
32.          
33.        </div>  
34.  
35.  
36.    </div>  
37.  
38.     
39.</div>  
40.  
41.</body>  
42.  
43.  
44.</html>  





这个代码有点乱,就将就这看吧,我是把这个页面放在自己的tomcat上的,其中这个html中大家发现
 



[html] view plain copy print?在CODE上查看代码片派生到我的代码片
01.<script type="text/javascript">  
02.    function callAndroidAction(action) {  
03.        Android.showToast();  
04.        alert("我敢保证,你现在用的是演示一");  
05.    }  
06.   function forSmallPhoto(action) {  
07.        alert("我敢保证,你现在用的是演示一"+action);  
08.    }  
09.</script>  





  

这个js方法没,看见里面的Android标识符没,没错,后台就是这么调用我们代码的,Android.showToast();就是这么调用的,就是这么简单,不要想的太难,我们就需按我上面说的那样,把Object实现,把标识符写好就ok了。饭后,后台就会通过标识符和你Object的方法名字调用你的方法。这里要说一下,你Object(即JavaScriptInterface,我们上面已经实现)里的方法的参数要和后台调用你的方法的参数个数和类型一直,就像我们平时调用方法是一样的。这一点知道了就好了。

这样就可以了。

所以WebViewActivity里面加上这一句就可以了。



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.view.addJavascriptInterface(new JavaScriptInterface(),"Android");  




 

这样js就说完了。

模版

当后台要调用我们的代码,我们就写一个方法,如果调用多次我们就写多个,这样太麻烦,所以我们来写一个通用的方法,就是无论后台调用你代码干不同的事,都调用你这个方法,那怎么区分不同的执行动作呢?用传的参数,我们在JavaScriptInterface里面写一个方法,这里就叫callAndroidAction,我设计的是给这个方法三个参数,

public void callAndroidAction(String action, String url,String json),*个参数action,即用来表示要执行的动作,第二个则是url,不管是服务其给的下载路径还是,访问其他页面的路径,在一个json就是其他一些参数,由于传的参数不固定,我们就用一个参数,一个参数时就传过来,多个参数时可以通过json字符串传过来,就没必要麻烦一个一个的写参数了。

然后我们在设计一个回调,让操作的代码拿出去,怎大体就是这样了



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.import java.util.HashMap;  
02.import java.util.Map;  
03.  
04.import android.content.Context;  
05.import android.os.Handler;  
06.import android.os.Message;  
07.import android.text.TextUtils;  
08.import android.util.Log;  
09.import android.webkit.JavascriptInterface;  
10.import android.widget.Toast;  
11.  
12./** 
13. *  
14. * Title: JavaScriptInterface.java Description: 
15. *  
16. * @author Liusong 
17. * @version V1.0 
18. */  
19.public class JavaScriptInterface {  
20.      
21.    private Handler mHandler;  
22.      
23.    /** Instantiate the interface and set the context */  
24.    public JavaScriptInterface(Handler handler) {  
25.        mHandler = handler;  
26.    }  
27.  
28.    /** Show a toast from the web page */  
29.    @JavascriptInterface  
30.    public void showToast(final String toast) {  
31.        Log.i("TAG", "调用成功==================》》》》》");  
32.    }  
33.  
34.    @JavascriptInterface  
35.    public void callAndroidAction(String action, String url,String json) {  
36.        Map<String, String> params = new HashMap<String, String>();  
37.        if(!TextUtils.isEmpty(url)){  
38.            params.put("url", url);  
39.        }  
40.        if(!TextUtils.isEmpty(json)){  
41.            params.put("json", json);  
42.        }  
43.        Message msg = Message.obtain();  
44.        msg.what = Integer.valueOf(action);  
45.        msg.obj = params;  
46.        mHandler.sendMessage(msg);  
47.    }  
48.}  





这样我们就从服务其拿到的参数都给Handler了,则WebViewActivity里面就要这样写了



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.import java.util.HashMap;  
02.import java.util.Map;  
03.  
04.import android.app.Activity;  
05.import android.os.Bundle;  
06.import android.os.Handler;  
07.import android.os.Message;  
08.import android.webkit.WebSettings;  
09.import android.webkit.WebView;  
10.  
11.public class WebViewActivity extends Activity {  
12.    private static final String url = "http://192.168.30.199:8080/song/test.html";  
13.      
14.    //执行动作  
15.    public static final int SELECT_IMAGE = 0;// 打开图库  
16.    public static final int OPEN_PAGE = 1;// 跳转其他特定页面  
17.    public static final int CLOSE_OR_BACK = 2;// 关闭或  
18.      
19.    private WebView mWebView;  
20.    @Override  
21.    protected void onCreate(Bundle savedInstanceState) {  
22.        super.onCreate(savedInstanceState);  
23.        setContentView(R.layout.activity_webviw);  
24.        initView();  
25.    }  
26.   <p>  
27.     private void getIntentDatas() {  
28.          // TODO Auto-generated method stub  
29.        url = getIntent().getStringExtra("url");  
30.   }</p><p> </p>    private void initView() {  
31.        mWebView = (WebView) findViewById(R.id.webview);  
32.        //或的WebView的Setting  
33.        WebSettings settings = mWebView.getSettings();  
34.        //设置支持js,看方法名字就知道啥意思  
35.        settings.setJavaScriptEnabled(true);  
36.        mWebView.addJavascriptInterface(new JavaScriptInterface(handler), "Android");  
37.        //加载网页路径  
38.        mWebView.loadUrl(url);  
39.    }  
40.      
41.    private Handler handler = new Handler(){  
42.        public void handleMessage(Message msg) {  
43.            switch (msg.what) {  
44.            case SELECT_IMAGE://执行打开图库,  
45.                  
46.                //如果有参数,取服务端传过来的参数(url,json)  
47.                Map<String, String> params = (HashMap<String, String>)msg.obj;  
48.                break;  
49.                  
50.            //其他功能,可随着自己功能的增加,在这里增加,只需和后台商量好动作的action值即可  
51.            default:  
52.                break;  
53.            }  
54.        };  
55.    };  
56.}  




*后再让WebViewActivity通用,就是通过传url参数



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.private void getIntentDatas() {  
02. // TODO Auto-generated method stub  
03. url = getIntent().getStringExtra("url");  
04.}
复制代码
复制代码

前三季度国民经济总体保持恢复态势

(2021年10月18日) 国家统计局   前三季度,面对复杂严峻的国内外环境,在以*同志为核心的党中央坚强领导下,各地区各部门认真贯彻落实党中央、国务院决策部署,科学统筹疫情防控和经济社会发展,强化宏观政策跨周期调节,有效应对疫情汛情等多重考验,国民经济持续恢复发展,主要宏观指标总体处于合理区间,就业形势基本稳定,居民收入继续增加,国际收支保持平衡,经济结构调整优化,质量效益稳步提升,社会大局和谐稳定。   初步核算,前三季度国内生产总值823131亿元,按可比价格计算,同比增长9.8%,两年平均增长5.2%,比上半年两年平均增速回落0.1个百分点。分季度看,一季度同比增长18.3%,两年平均增长5.0%;二季度同比增长7.9%,两年平均增长5.5%;三季度同比增长4.9%,两年平均增长4.9%。分产业看,前三季度*产业增加值51430亿元,同比增长7.4%,两年平均增长4.8%;第二产业增加值320940亿元,同比增长10.6%,两年平均增长5.7%;第三产业增加值450761亿元,同比增长9.5%,两年平均增长4.9%。从环比看,三季度国内生产总值增长0.2%。   一、农业生产形势较好,畜牧业生产快速增长   前三季度,农业(种植业)增加值同比增长3.4%,两年平均增长3.6%。全国夏粮早稻产量合计17384万吨(3477亿斤),比上年增加369万吨(74亿斤),增长2.2%。秋粮播种面积稳中有增,其中,玉米播种面积增加较多;主要秋粮作物总体长势较好,全年粮食生产有望再获丰收。前三季度,猪牛羊禽肉产量6428万吨,同比增长22.4%,其中猪肉、羊肉、牛肉、禽肉产量同比分别增长38.0%、5.3%、3.9%、3.8%;牛奶产量同比增长8.0%,禽蛋产量下降2.4%。三季度末,生猪存栏43764万头,同比增长18.2%;其中,能繁殖母猪存栏4459万头,增长16.7%。   二、工业生产持续增长,企业效益稳步提升   前三季度,全国规模以上工业增加值同比增长11.8%,两年平均增长6.4%。9月份,规模以上工业增加值同比增长3.1%,两年平均增长5.0%;环比增长0.05%。分三大门类看,前三季度采矿业增加值同比增长4.7%,制造业增长12.5%,电力、热力、燃气及水生产和供应业增长12.0%。高技术制造业增加值同比增长20.1%,两年平均增长12.8%。分产品看,前三季度新能源汽车、工业机器人、集成电路产量同比分别增长172.5%、57.8%、43.1%,两年平均增速均超过28%。分经济类型看,前三季度国有控股企业增加值同比增长9.6%;股份制企业增长12.0%,外商及港澳台商投资企业增长11.6%;私营企业增长13.1%。9月份,制造业采购经理指数(PMI)为49.6%,其中高技术制造业PMI为54.0%,高于上月0.3个百分点;企业生产经营活动预期指数为56.4%。   1-8月份,全国规模以上工业企业实现利润总额56051亿元,同比增长49.5%,两年平均增长19.5%;规模以上工业企业营业收入利润率为7.01%,同比提高1.20个百分点。   三、服务业稳步恢复,现代服务业增势较好   前三季度,第三产业持续增长。分行业看,前三季度信息传输、软件和信息技术服务业,交通运输、仓储和邮政业增加值同比分别增长19.3%、15.3%,两年平均分别增长17.6%、6.2%。9月份,全国服务业生产指数同比增长5.2%,比上月加快0.4个百分点;两年平均增长5.3%,加快0.9个百分点。1-8月份,全国规模以上服务业企业营业收入同比增长25.6%,两年平均增长10.7%。   9月份,服务业商务活动指数为52.4%,高于上月7.2个百分点。从行业情况看,上月受疫情汛情冲击较为严重的铁路运输、航空运输、住宿、餐饮、生态保护及环境治理等行业商务活动指数均大幅回升至临界点以上。从市场预期看,服务业业务活动预期指数为58.9%,高于上月1.6个百分点,其中铁路运输、航空运输、邮政快递等行业均高于65.0%。   四、市场销售保持增长,升级类和基本生活类商品销售增长较快   前三季度,社会消费品零售总额318057亿元,同比增长16.4%,两年平均增长3.9%。9月份,社会消费品零售总额36833亿元,同比增长4.4%,比上月加快1.9个百分点;两年平均增长3.8%,加快2.3个百分点;环比增长0.30%。按经营单位所在地分,前三季度城镇消费品零售额275888亿元,同比增长16.5%,两年平均增长3.9%;乡村消费品零售额42169亿元,同比增长15.6%,两年平均增长3.8%。按消费类型分,前三季度商品零售285307亿元,同比增长15.0%,两年平均增长4.5%;餐饮收入32750亿元,同比增长29.8%,两年平均下降0.6%。按商品类别分,前三季度限额以上单位金银珠宝类、体育娱乐用品类、文化办公用品类等升级类商品零售额同比分别增长41.6%、28.6%、21.7%;饮料类、服装鞋帽针纺织品类、日用品类等基本生活类商品零售额同比分别增长23.4%、20.6%、16.0%。前三季度,全国网上零售额91871亿元,同比增长18.5%。其中,实物商品网上零售额75042亿元,同比增长15.2%;占社会消费品零售总额的比重为23.6%。   五、固定资产投资规模扩大,高技术产业和社会领域投资快速增长   前三季度,全国固定资产投资(不含农户)397827亿元,同比增长7.3%,两年平均增长3.8%;9月份环比增长0.17%。分领域看,前三季度基础设施投资同比增长1.5%,两年平均增长0.4%;制造业投资同比增长14.8%,两年平均增长3.3%;房地产开发投资同比增长8.8%,两年平均增长7.2%。全国商品房销售面积130332万平方米,同比增长11.3%,两年平均增长4.6%;商品房销售额134795亿元,同比增长16.6%,两年平均增长10.0%。分产业看,前三季度*产业投资同比增长14.0%,第二产业投资增长12.2%,第三产业投资增长5.0%。民间投资同比增长9.8%,两年平均增长3.7%。高技术产业投资同比增长18.7%,两年平均增长13.8%;其中高技术制造业和高技术服务业投资同比分别增长25.4%、6.6%。高技术制造业中,计算机及办公设备制造业、航空航天器及设备制造业投资同比分别增长40.8%、38.5%;高技术服务业中,电子商务服务业、检验检测服务业投资同比分别增长43.8%、23.7%。社会领域投资同比增长11.8%,两年平均增长10.5%;其中卫生投资、教育投资同比分别增长31.4%、10.4%。   六、货物进出口较快增长,贸易结构持续改善   前三季度,货物进出口总额283264亿元,同比增长22.7%。其中,出口155477亿元,增长22.7%;进口127787亿元,增长22.6%;进出口相抵,贸易顺差27691亿元。9月份,进出口总额35329亿元,同比增长15.4%。其中,出口19830亿元,增长19.9%;进口15498亿元,增长10.1%。前三季度,机电产品出口同比增长23%,高于整体出口增速0.3个百分点,占出口总额的比重为58.8%。一般贸易进出口占进出口总额的比重为61.8%,比上年同期提高1.4个百分点。民营企业进出口同比增长28.5%,占进出口总额的比重为48.2%。   七、居民消费价格温和上涨,工业生产者出厂价格涨幅扩大   前三季度,全国居民消费价格(CPI)同比上涨0.6%,涨幅比上半年扩大0.1个百分点。其中,9月份全国居民消费价格同比上涨0.7%,涨幅比上月回落0.1个百分点;环比持平。前三季度,城市居民消费价格上涨0.7%,农村居民消费价格上涨0.4%。分类别看,前三季度食品烟酒价格同比下降0.5%,衣着价格上涨0.2%,居住价格上涨0.6%,生活用品及服务价格上涨0.2%,交通通信价格上涨3.3%,教育文化娱乐价格上涨1.6%,医疗保健价格上涨0.3%,其他用品及服务价格下降1.6%。在食品烟酒价格中,猪肉价格同比下降28.0%,粮食价格上涨1.0%,鲜菜价格上涨1.3%,鲜果价格上涨2.7%。前三季度,扣除食品和能源价格后的核心CPI同比上涨0.7%,涨幅比上半年扩大0.3个百分点。   前三季度,全国工业生产者出厂价格同比上涨6.7%,涨幅比上半年扩大1.6个百分点;其中9月份同比上涨10.7%,环比上涨1.2%。前三季度,全国工业生产者购进价格同比上涨9.3%,涨幅比上半年扩大2.2个百分点;其中9月份同比上涨14.3%,环比上涨1.1%。   八、就业形势基本稳定,城镇调查失业率稳中有降   前三季度,全国城镇新增就业1045万人,完成全年目标的95.0%。9月份,全国城镇调查失业率为4.9%,比上月下降0.2个百分点,比上年同期下降0.5个百分点。本地户籍人口调查失业率为5.0%,外来户籍人口调查失业率为4.8%。16-24岁人口、25-59岁人口调查失业率分别为14.6%、4.2%。31个大城市城镇调查失业率为5.0%,比上月下降0.3个百分点。全国企业就业人员周平均工作时间为47.8小时,比上月增加0.3小时。三季度末,外出务工农村劳动力总量18303万人,比二季度末增加70万人。   九、居民收入与经济增长基本同步,城乡居民人均收入比缩小   前三季度,全国居民人均可支配收入26265元,同比名义增长10.4%,两年平均增长7.1%;扣除价格因素同比实际增长9.7%,两年平均增长5.1%,与经济增长基本同步。按常住地分,城镇居民人均可支配收入35946元,同比名义增长9.5%,实际增长8.7%;农村居民人均可支配收入13726元,同比名义增长11.6%,实际增长11.2%。从收入来源看,全国居民人均工资性收入、经营净收入、财产净收入、转移净收入同比分别名义增长10.6%、12.4%、11.4%、7.9%。城乡居民人均收入比值2.62,比上年同期缩小0.05。全国居民人均可支配收入中位数22157元,同比名义增长8.0%。   总的来看,前三季度国民经济总体保持恢复态势,结构调整稳步推进,推动高质量发展取得新进展。但也要看到,当前国际环境不确定性因素增多,国内经济恢复仍不稳固、不均衡。下一步,要坚持以*新时代中国特色社会主义思想为指导,按照党中央、国务院决策部署,坚持稳中求进工作总基调,完整准确全面贯彻新发展理念,加快构建新发展格局,抓好常态化疫情防控,强化宏观政策跨周期调节,着力促进经济持续健康发展,着力深化改革开放创新,不断激发市场活力、增强发展动力、释放内需潜力,努力保持经济运行在合理区间,确保完成全年经济社会发展主要目标任务。   附注   (1)两年平均增速是指以2019年相应同期数为基数,采用几何平均的方法计算的增速。   (2)国内生产总值、规模以上工业增加值及其分类项目增长速度按可比价计算,为实际增长速度;其他指标除特殊说明外,按现价计算,为名义增长速度。   (3)根据季节调整模型自动修正结果,对近一年来各期国内生产总值、规模以上工业增加值、固定资产投资(不含农户)、社会消费品零售总额环比增速进行修订。修订结果及2021年三季度GDP环比数据、2021年9月份其他指标环比数据如下:   2020年以来各季度GDP环比增速分别为-9.5%、10.7%、2.9%、3.2%、0.2%、1.2%和0.2%。 其他指标环比数据表    规模以上工业增加值 环比增速(%) 固定资产投资 (不含农户) 环比增速(%) 社会消费品零售总额 环比增速(%) 2020年9月份 1.03 0.11  3.73 10月份 0.70 0.19  0.16 11月份 0.60 0.18  1.12 12月份 0.63 0.19  0.79 2021年1月份 0.64 0.00 -0.20 2月份 0.66 0.07  0.79 3月份 0.60 0.05  0.70 4月份 0.52 0.11  0.01 5月份 0.51 0.14  0.67 6月份 0.50 0.14  0.43 7月份 0.25 0.08 -0.23 8月份 0.31 0.18  0.22 9月份 0.05 0.17  0.30    (4)规模以上工业的统计范围为年主营业务收入2000万元及以上的工业企业。   由于规模以上工业企业范围每年发生变化,为保证本年数据与上年可比,计算产品产量等各项指标同比增长速度所采用的同期数与本期的企业统计范围尽可能相一致,和上年公布的数据存在口径差异。主要原因:一是统计单位范围发生变化。每年有部分企业达到规模纳入调查范围,也有部分企业因规模变小退出调查范围,还有新建投产企业、破产、注(吊)销企业等影响。二是部分企业集团(公司)产品产量数据存在跨地区重复统计现象,根据专项调查对企业集团(公司)跨地区重复产量进行了剔重。   (5)服务业生产指数是指剔除价格因素后,服务业报告期相对于基期的产出变化。   (6)社会消费品零售总额统计范围是从事商品零售活动或提供餐饮服务的法人企业、产业活动单位和个体户。其中,限额以上单位是指年主营业务收入2000万元及以上的批发业企业(单位)、500万元及以上的零售业企业(单位)、200万元及以上的住宿和餐饮业企业(单位)。   由于限额以上批发和零售业、住宿和餐饮业企业(单位)范围每年发生变化,为保证本年数据与上年可比,计算限额以上单位消费品零售额等各项指标同比增长速度所采用的同期数与本期的企业(单位)统计范围相一致,和上年公布的数据存在口径差异。主要原因是每年都有部分企业(单位)达到限额标准纳入调查范围,同时也有部分企业(单位)因规模变小达不到限额标准退出调查范围,还有新开业企业、破产、注(吊)销企业(单位)的影响。   网上零售额是指通过公共网络交易平台(包括自建网站和第三方平台)实现的商品和服务零售额之和。商品和服务包括实物商品和非实物商品(如虚拟商品、服务类商品等)。   社会消费品零售总额包括实物商品网上零售额,不包括非实物商品网上零售额。   (7)根据统计执法检查和统计调查制度规定,对上年同期固定资产投资数据进行修订,增速按可比口径计算。   (8)就业人员是指16周岁及以上,有劳动能力,为取得劳动报酬或经营收入而从事一定社会劳动的人员。   (9)全国居民人均可支配收入中位数是指将所有调查户按人均可支配收入水平从低到高顺序排列,处于*中间位置的调查户的人均可支配收入。   (10)进出口数据来源于海关总署;城镇新增就业人员数据来源于人力资源和社会保障部。   (11)部分数据因四舍五入,存在总计与分项合计不等的情况。   附表 2021年9月份及前三季度主要统计数据  指 标 9月 1-9月 *对量 同比增长 (%) *对量 同比增长 (%) 一、国内生产总值(亿元) 290964 (三季度) 4.9 (三季度) 823131 9.8 *产业 23028 (三季度) 7.1 (三季度) 51430 7.4 第二产业 113786 (三季度) 3.6 (三季度) 320940  10.6 第三产业 154150 (三季度) 5.4 (三季度) 450761 9.5 二、农业         猪牛羊禽肉(万吨) … … 6428 22.4 其中:猪肉(万吨) … … 3917 38.0 生猪存栏(万头) … … 43764 18.2 生猪出栏(万头) … … 49193 35.9 三、规模以上工业增加值 … 3.1 … 11.8 (一)分三大门类         采矿业 … 3.2 … 4.7 制造业 … 2.4 … 12.5 电力、热力、燃气及水生产和供应业 … 9.7 … 12.0 (二)分经济类型         其中:国有控股企业 … 4.5 … 9.6 其中:股份制企业 … 4.0 … 12.0    外商及港澳台商投资企业 … 0.4 … 11.6 其中:私营企业 … 2.8 … 13.1 (三)主要行业增加值         纺织业 … -5.8 … 3.7 化学原料和化学制品制造业 … 0.0 … 10.8 非金属矿物制品业 … -1.1 … 12.6 黑色金属冶炼和压延加工业 … -9.7 … 5.0 通用设备制造业 … 3.0 … 17.1 汽车制造业 … -8.2 … 9.4 铁路、船舶、航空航天和其他运输设备制造业 … 7.9 … 11.3 电气机械和器材制造业 … 6.8 … 21.4 计算机、通信和其他电子设备制造业 … 9.5 … 16.8 电力、热力生产和供应业 … 8.9 … 11.4 (四)主要产品产量         发电量(亿千瓦时) 6751 4.9 60721 10.7 生铁 (万吨) 6519 -16.1 67107 -1.3 粗钢 (万吨) 7375 -21.2 80589 2.0 钢材 (万吨) 10195 -14.8 102035 4.6 水泥 (万吨) 20504 -13.0 177770 5.3 原油加工量(万吨) 5607 -2.6 52687 6.2 十种有色金属 (万吨) 523 -1.6 4842 7.9 原煤(万吨) 33410 -0.9 293059 3.7 焦炭(万吨) 3718 -9.6 35745 1.3 硫酸(折100%) (万吨) 794 1.6 7045 7.4 烧碱(折100%) (万吨) 312 -1.4 2851 6.3 乙烯 (万吨) 223 9.3 2089 23.1 化学纤维 (万吨) 534 -2.0 5037 13.5 平板玻璃 (万重量箱) 8423 4.4 76376 9.9 微型计算机设备 (万台) 4334 12.0 33833 30.7 集成电路 (亿块) 304 21.4 2675 43.1 汽车 (万辆) 218.6 -13.7 1855.4 9.4 其中:轿车 (万辆) 82.5 -9.5 678.0 10.0 (五)产品销售率(%) 98.2 -0.4 (百分点) 97.8 0.1 (百分点) (六)出口交货值(亿元) 13391 16.8 103664 19.4 四、服务业生产指数 … 5.2 … 16.3 五、固定资产投资(不含农户) (亿元) … … 397827 7.3 其中:民间投资 … … 227473 9.8 分产业         *产业 … … 10395 14.0 第二产业 … … 119071 12.2 第三产业 … … 268360 5.0 全国建筑业总产值(亿元)   … … 191283 13.9  全国建筑业房屋建筑施工面积 (亿平方米) … … 135.0 8.4 六、房地产开发         (一)房地产开发投资(亿元) … … 112568 8.8 其中:住宅 … … 84906 10.9    办公楼 … … 4446 -0.5    商业营业用房 … … 9423 -1.3 (二)房屋施工面积(万平方米) … … 928065 7.9 其中:住宅 … … 656884 8.2    办公楼 … … 35993 2.5    商业营业用房 … … 87465 -0.7 (三)房屋新开工面积(万平方米) … … 152944 -4.5 其中:住宅 … … 113374 -3.3    办公楼 … … 3847 -20.3    商业营业用房 … … 10778 -17.5 (四)房屋竣工面积(万平方米) … … 51013 23.4 其中:住宅 … … 36816 24.4    办公楼 … … 1662 17.4    商业营业用房 … … 4632 10.3 (五)商品房销售面积(万平方米) … … 130332 11.3 其中:住宅 … … 115432 11.4    办公楼 … … 2257 3.1    商业营业用房 … … 5972 0.7 (六)商品房销售额(亿元) … … 134795 16.6 其中:住宅 … … 121957 17.8    办公楼 … … 3179 0.5    商业营业用房 … … 6437 0.5 (七)房地产开发企业到位资金 (亿元) … … 151486 11.1 其中:国内贷款 … … 18770 -8.4   利用外资 … … 59 -36.9   自筹资金 … … 47212 6.1   定金及预收款 … … 56689 25.6   个人按揭贷款 … … 24124 10.7 土地购置面积(万平方米) … … 13730 -8.5 商品房待售面积(万平方米) … … 50285 1.4 七、社会消费品零售总额(亿元) 36833 4.4 318057 16.4 其中:限额以上单位消费品零售额 13902 2.8 117588 17.9 (一)按经营地分         城镇 31462 4.2 275888 16.5 乡村 5371 5.4 42169 15.6 (二)按消费类型分         餐饮收入 3831 3.1 32750 29.8 其中:限额以上单位餐饮收入 903 5.5 7553 34.8 商品零售 33002 4.5 285307 15.0 其中:限额以上单位商品零售 12999 2.7 110035 17.0  粮油、食品类 1506 9.2 12087 10.3  饮料类 262 10.1 2088 23.4  烟酒类 490 16.0 3430 25.8  服装鞋帽、针纺织品类 1063 -4.8 9641 20.6  化妆品类 317 3.9 2783 17.9  金银珠宝类 263 20.1 2246 41.6  日用品类 584 0.5 5261 16.0  家用电器和音像器材类 739 6.6 6580 13.5  中西药品类 508 8.6 4196 10.5  文化办公用品类 396 22.6 2877 21.7  家具类 151 3.4 1205 20.7  通讯器材类 508 22.8 4323 17.5  石油及制品类 1840 17.3 14900 20.3  汽车类 3535 -11.8 32066 15.5  建筑及装潢材料类 175 13.3 1379 24.9 八、进出口(亿元)         进出口总额 35329 15.4 283264 22.7 出口额 19830 19.9 155477 22.7 进口额 15498 10.1 127787 22.6 九、居民消费价格 … 0.7 … 0.6 其中:城市 … 0.8 … 0.7    农村 … 0.2 … 0.4 其中:食品 … -5.2 … -1.6    非食品 … 2.0 … 1.1 其中:消费品 … 0.2 … 0.6    服务 … 1.4 … 0.7 分类别         食品烟酒 … -2.8 … -0.5  衣着 … 0.5 … 0.2  居住 … 1.3 … 0.6  生活用品及服务 … 0.5 … 0.2  交通通信 … 5.8 … 3.3  教育文化娱乐 … 3.2 … 1.6  医疗保健 … 0.4 … 0.3  其他用品及服务 … -2.8 … -1.6 十、工业生产者出厂价格 … 10.7 … 6.7 生产资料 … 14.2 … 8.9  采掘 … 49.4 … 26.7  原材料 … 20.4 … 13.2  加工 … 8.9 … 5.6 生活资料 … 0.4 … 0.2  食品 … 0.7 … 1.5  衣着 … 0.4 … -0.6  一般日用品 … 0.4 … 0.2  耐用消费品 … 0.2 … -0.8 十一、工业生产者购进价格 … 14.3 … 9.3 燃料、动力类 … 30.3 … 14.1 黑色金属材料类 … 23.3 … 20.9 有色金属材料及电线类 … 22.6 … 20.1 化工原料类 … 20.7 … 12.3 木材及纸浆类 … 7.2 … 4.9 建筑材料及非金属类 … 7.9 … 2.8 其它工业原材料及半成品类 … 4.9 … 2.7 农副产品类 … 2.6 … 4.9 纺织原料类 … 7.6 … 3.5 十二、农产品生产者价格 … -8.0 (三季度) … -1.1 农业产品 … 6.5 (三季度) … 10.7 谷物 … 9.8 (三季度) … 17.6 小麦 … 8.5 (三季度) … 6.4 稻谷 … 2.5 (三季度) … 3.1 玉米 … 21.0 (三季度) … 31.2 油料 … 6.3 (三季度) … 5.2 蔬菜 … -1.8 (三季度) … 1.5 水果 … 4.8 (三季度) … 1.1 茶叶 … 0.9 (三季度) … 2.4 林业产品 … 6.6 (三季度) … 3.9 木材 … 5.3 (三季度) … 1.3 饲养动物及其产品 … -29.0 (三季度) … -15.8 生猪 … -55.5 (三季度) … -31.4 活牛 … 2.9 (三季度) … 6.8 活羊 … 0.0 (三季度) … 4.7 活家禽 … 3.1 (三季度) … 4.6 禽蛋 … 17.6 (三季度) … 14.6 渔业产品 … 10.2 (三季度) … 10.3 十三、居民收入和支出(元/人)         (一)全国居民人均可支配收入 … … 26265 9.7 按常住地分          城镇居民 … … 35946 8.7  农村居民 … … 13726 11.2 按收入来源分          工资性收入 … … 14917 10.6  经营净收入 … … 4136 12.4  财产净收入 … … 2329 11.4  转移净收入 … … 4884 7.9 (二)全国居民人均可支配收入中位数 … … 22157 8.0 (三)全国居民人均消费支出 … … 17275 15.1 城镇居民 … … 21981 13.4 农村居民 … … 11179 18.1 (四)外出务工农村劳动力 (万人,三季度末) … … 18303 2.0 外出务工农村劳动力月均收入(元/人) … … 4454 10.4 注: 1.国内生产总值、规模以上工业增加值及其分类项目增长速度均按可比价计算;全国及分城乡居民人均可支配收入和人均消费支出增速为实际增长速度,全国居民人均可支配收入分项增速、中位数增速为名义增速;其他指标增长速度均按现价计算。 2.全国建筑业企业指具有资质等级的总承包和专业承包建筑业企业,不含劳务分包建筑业企业。 3.农产品生产者价格指农产品生产者直接出售其产品时的价格。 4.进出口数据来源于海关总署。 5.此表中部分数据因四舍五入,存在总计与分项合计不等的情况。    附图        

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速